1/* SOGoWebDAVAclManager.m - this file is part of SOGo 2 * 3 * Copyright (C) 2008-2015 Inverse inc. 4 * 5 * This file is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2, or (at your option) 8 * any later version. 9 * 10 * This file is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; see the file COPYING. If not, write to 17 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 * Boston, MA 02111-1307, USA. 19 */ 20 21#import <Foundation/NSArray.h> 22#import <Foundation/NSEnumerator.h> 23#import <Foundation/NSString.h> 24#import <Foundation/NSValue.h> 25 26#import <NGObjWeb/SoClass.h> 27#import <NGObjWeb/SoClassSecurityInfo.h> 28#import <NGExtensions/NSObject+Logs.h> 29 30#import "NSDictionary+Utilities.h" 31#import "NSObject+DAV.h" 32#import "SOGoObject.h" 33#import "SOGoUser.h" 34#import "SOGoWebDAVValue.h" 35 36#import "SOGoWebDAVAclManager.h" 37 38static NSNumber *yesObject = nil; 39 40@interface SoClass (SOGoDAVPermissions) 41 42- (BOOL) userRoles: (NSArray *) userRoles 43 havePermission: (NSString *) permission; 44 45@end 46 47@implementation SoClass (SOGoDAVPermissions) 48 49- (BOOL) userRoles: (NSArray *) userRoles 50 havePermission: (NSString *) permission 51{ 52 BOOL result; 53 SoClass *currentClass; 54 NSArray *roles; 55 56 result = NO; 57 58 currentClass = self; 59 while (!result && currentClass) 60 { 61 roles = [[currentClass soClassSecurityInfo] 62 defaultRolesForPermission: permission]; 63 if ([roles firstObjectCommonWithArray: userRoles]) 64 { 65 // NSLog (@"matched '%@': %@", permission, roles); 66 result = YES; 67 } 68 else 69 currentClass = [currentClass soSuperClass]; 70 } 71 72 return result; 73} 74 75@end 76 77@implementation SOGoWebDAVAclManager 78 79+ (void) initialize 80{ 81 if (!yesObject) 82 { 83 yesObject = [NSNumber numberWithBool: YES]; 84 [yesObject retain]; 85 } 86} 87 88- (id) init 89{ 90 if ((self = [super init])) 91 { 92 aclTree = [NSMutableDictionary new]; 93 [self registerDAVPermission: davElement (@"all", @"DAV:") 94 abstract: YES 95 withEquivalent: nil 96 asChildOf: nil]; 97 } 98 99 return self; 100} 101 102- (void) dealloc 103{ 104 [aclTree release]; 105 [super dealloc]; 106} 107 108- (void) _registerChild: (NSMutableDictionary *) newEntry 109 of: (NSDictionary *) parentPermission 110{ 111 NSString *identifier; 112 NSMutableDictionary *parentEntry; 113 NSMutableArray *children; 114 115 identifier = [parentPermission keysWithFormat: @"{%{ns}}%{method}"]; 116 parentEntry = [aclTree objectForKey: identifier]; 117 if (parentEntry) 118 { 119 children = [parentEntry objectForKey: @"children"]; 120 if (!children) 121 { 122 children = [NSMutableArray array]; 123 [parentEntry setObject: children forKey: @"children"]; 124 } 125 [children addObject: newEntry]; 126 [newEntry setObject: parentEntry forKey: @"parent"]; 127 } 128 else 129 [self errorWithFormat: @"parent entry '%@' does not exist in DAV" 130 @" permissions table", identifier]; 131} 132 133- (void) registerDAVPermission: (NSDictionary *) davPermission 134 abstract: (BOOL) abstract 135 withEquivalent: (NSString *) sogoPermission 136 asChildOf: (NSDictionary *) otherDAVPermission 137{ 138 NSMutableDictionary *newEntry; 139 NSString *identifier; 140 141 newEntry = [NSMutableDictionary new]; 142 identifier = [davPermission keysWithFormat: @"{%{ns}}%{method}"]; 143 if ([aclTree objectForKey: identifier]) 144 [self warnWithFormat: 145 @"entry '%@' already exists in DAV permissions table", 146 identifier]; 147 [aclTree setObject: newEntry forKey: identifier]; 148 [newEntry setObject: davPermission forKey: @"permission"]; 149 if (abstract) 150 [newEntry setObject: yesObject forKey: @"abstract"]; 151 if (sogoPermission) 152 [newEntry setObject: sogoPermission forKey: @"equivalent"]; 153 154 if (otherDAVPermission) 155 [self _registerChild: newEntry of: otherDAVPermission]; 156 157 [newEntry release]; 158} 159 160#warning this method should be simplified! 161/* We add the permissions that fill those conditions: 162 - should match the sogo permissions implied by the user roles 163 If all the child permissions of a permission are included, then this 164 permission will be included too. Conversely, if a permission is included, 165 all the child permissions will be included too. */ 166 167- (BOOL) _fillArray: (NSMutableArray *) davPermissions 168 withPermission: (NSDictionary *) permission 169 forUserRoles: (NSArray *) userRoles 170 withSoClass: (SoClass *) soClass 171 matchSOGoPerms: (BOOL) matchSOGoPerms 172{ 173 NSString *sogoPermission; 174 NSDictionary *childPermission; 175 NSEnumerator *children; 176 BOOL appended, childrenAppended; 177 178 // NSLog (@"attempt to add permission: %@", 179 // [permission objectForKey: @"permission"]); 180 appended = YES; 181 if (matchSOGoPerms) 182 { 183 sogoPermission = [permission objectForKey: @"equivalent"]; 184 if (sogoPermission 185 && [soClass userRoles: userRoles havePermission: sogoPermission]) 186 [davPermissions addObject: [permission objectForKey: @"permission"]]; 187 else 188 appended = NO; 189 // NSLog (@"permission '%@' appended: %d", sogoPermission, appended); 190 } 191 else 192 [davPermissions 193 addObject: [permission objectForKey: @"permission"]]; 194 195 children = [[permission objectForKey: @"children"] objectEnumerator]; 196 if (children) 197 { 198 childrenAppended = YES; 199 while ((childPermission = [children nextObject])) 200 childrenAppended &= [self _fillArray: davPermissions 201 withPermission: childPermission 202 forUserRoles: userRoles 203 withSoClass: soClass 204 matchSOGoPerms: (matchSOGoPerms 205 && !appended)]; 206 if (childrenAppended && !appended) 207 { 208 // NSLog (@" adding perm '%@' because children were appended", 209 // [permission objectForKey: @"permission"]); 210 [davPermissions 211 addObject: [permission objectForKey: @"permission"]]; 212 appended = YES; 213 } 214 } 215 216 return appended; 217} 218 219- (NSArray *) davPermissionsForRoles: (NSArray *) roles 220 onObject: (SOGoObject *) object 221{ 222 NSMutableArray *davPermissions; 223 SoClass *soClass; 224 225 davPermissions = [NSMutableArray array]; 226 soClass = [[object class] soClass]; 227 [self _fillArray: davPermissions 228 withPermission: [aclTree objectForKey: @"{DAV:}all"] 229 forUserRoles: roles 230 withSoClass: soClass 231 matchSOGoPerms: YES]; 232 233 return davPermissions; 234} 235 236- (SOGoWebDAVValue *) 237 _supportedPrivilegeSetFromPermission: (NSDictionary *) perm 238{ 239 NSMutableArray *privilege; 240 NSEnumerator *children; 241 NSDictionary *currentPerm; 242 243 privilege = [NSMutableArray array]; 244 [privilege addObject: 245 davElementWithContent (@"privilege", 246 @"DAV:", 247 [perm objectForKey: @"permission"])]; 248 if ([[perm objectForKey: @"abstract"] boolValue]) 249 [privilege addObject: davElement (@"abstract", @"DAV:")]; 250 children = [[perm objectForKey: @"children"] objectEnumerator]; 251 while ((currentPerm = [children nextObject])) 252 [privilege addObject: 253 [self _supportedPrivilegeSetFromPermission: currentPerm]]; 254 255 return davElementWithContent (@"supported-privilege", 256 @"DAV:", privilege); 257} 258 259- (SOGoWebDAVValue *) treeAsWebDAVValue 260{ 261 return [self _supportedPrivilegeSetFromPermission: 262 [aclTree objectForKey: @"{DAV:}all"]]; 263} 264 265- (id) copyWithZone: (NSZone *) aZone 266{ 267 SOGoWebDAVAclManager *x; 268 269 x = [[SOGoWebDAVAclManager allocWithZone: aZone] init]; 270 x->aclTree = [aclTree mutableCopyWithZone: aZone]; 271 272 return x; 273} 274 275@end 276