RLMPermissionsTests.mm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2018 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import <XCTest/XCTest.h>
  19. #import "RLMSyncTestCase.h"
  20. #import "RLMTestUtils.h"
  21. #define APPLY_PERMISSION(ma_permission, ma_user) do { \
  22. XCTestExpectation *ex = [self expectationWithDescription:@"apply permission"]; \
  23. [ma_user applyPermission:ma_permission callback:^(NSError *err) { \
  24. XCTAssertNil(err, @"Received an error when applying permission: %@", err); \
  25. [ex fulfill]; \
  26. }]; \
  27. [self waitForExpectationsWithTimeout:10.0 handler:nil]; \
  28. } while (0) \
  29. @interface ObjectWithPermissions : RLMObject
  30. @property (nonatomic) int value;
  31. @property (nonatomic) RLMArray<RLMPermission *><RLMPermission> *permissions;
  32. @end
  33. @implementation ObjectWithPermissions
  34. @end
  35. @interface LinkToObjectWithPermissions : RLMObject
  36. @property (nonatomic) int value;
  37. @property (nonatomic) ObjectWithPermissions *link;
  38. @property (nonatomic) RLMArray<RLMPermission *><RLMPermission> *permissions;
  39. @end
  40. @implementation LinkToObjectWithPermissions
  41. @end
  42. @interface RLMPermissionsTests : RLMSyncTestCase
  43. @property (nonatomic, strong) RLMSyncUser *userA;
  44. @property (nonatomic, strong) RLMSyncUser *userB;
  45. @property (nonatomic, strong) RLMSyncUser *userC;
  46. @property (nonatomic, strong) void (^errorBlock)(NSError *);
  47. @end
  48. @implementation RLMPermissionsTests
  49. - (void)setUp {
  50. [super setUp];
  51. NSString *accountNameBase = [[NSUUID UUID] UUIDString];
  52. NSString *userNameA = [accountNameBase stringByAppendingString:@"a"];
  53. self.userA = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:userNameA register:YES]
  54. server:[RLMSyncTestCase authServerURL]];
  55. NSString *userNameB = [accountNameBase stringByAppendingString:@"b"];
  56. self.userB = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:userNameB register:YES]
  57. server:[RLMSyncTestCase authServerURL]];
  58. NSString *userNameC = [accountNameBase stringByAppendingString:@"c"];
  59. self.userC = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:userNameC register:YES]
  60. server:[RLMSyncTestCase authServerURL]];
  61. RLMSyncManager.sharedManager.errorHandler = ^(NSError *error, __unused RLMSyncSession *session) {
  62. if (self.errorBlock) {
  63. self.errorBlock(error);
  64. self.errorBlock = nil;
  65. } else {
  66. XCTFail(@"Error handler should not be called unless explicitly expected. Error: %@", error);
  67. }
  68. };
  69. }
  70. - (void)tearDown {
  71. [self.userA logOut];
  72. [self.userB logOut];
  73. [self.userC logOut];
  74. RLMSyncManager.sharedManager.errorHandler = nil;
  75. [super tearDown];
  76. }
  77. #pragma mark - Helper methods
  78. - (BOOL)isPartial {
  79. return YES;
  80. }
  81. - (NSError *)subscribeToRealm:(RLMRealm *)realm type:(Class)cls where:(NSString *)pred {
  82. RLMSyncSubscription *sub = [[cls objectsInRealm:realm where:pred] subscribe];
  83. id ex = [[XCTKVOExpectation alloc] initWithKeyPath:@"state" object:sub expectedValue:@(RLMSyncSubscriptionStateComplete)];
  84. [self waitForExpectations:@[ex] timeout:20.0];
  85. return sub.error;
  86. }
  87. - (NSURL *)createRealmWithName:(SEL)sel permissions:(void (^)(RLMRealm *realm))block {
  88. // Create a new Realm with an admin user
  89. RLMSyncUser *admin = [self createAdminUserForURL:[RLMSyncTestCase authServerURL]
  90. username:[[NSUUID UUID] UUIDString]];
  91. auto url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"realm://127.0.0.1:9080/%@", NSStringFromSelector(sel)]];
  92. RLMRealm *adminRealm = [self openRealmForURL:url user:admin];
  93. [self addSyncObjectsToRealm:adminRealm descriptions:@[@"child-1", @"child-2", @"child-3"]];
  94. CHECK_COUNT(3, SyncObject, adminRealm);
  95. [self waitForUploadsForRealm:adminRealm error:nil];
  96. [self waitForDownloadsForRealm:adminRealm error:nil];
  97. // FIXME: we currently need to add a subscription to get the permissions types sent to us
  98. [adminRealm refresh];
  99. CHECK_COUNT(0, SyncObject, adminRealm);
  100. [self subscribeToRealm:adminRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  101. CHECK_COUNT(3, SyncObject, adminRealm);
  102. // Set up permissions on the Realm
  103. [adminRealm transactionWithBlock:^{ block(adminRealm); }];
  104. // FIXME: we currently need to also add the old realm-level permissions
  105. RLMSyncPermission *p = [[RLMSyncPermission alloc] initWithRealmPath:[url path]
  106. identity:self.userA.identity
  107. accessLevel:RLMSyncAccessLevelRead];
  108. APPLY_PERMISSION(p, admin);
  109. p = [[RLMSyncPermission alloc] initWithRealmPath:[url path] identity:self.userB.identity
  110. accessLevel:RLMSyncAccessLevelRead];
  111. APPLY_PERMISSION(p, admin);
  112. p = [[RLMSyncPermission alloc] initWithRealmPath:[url path] identity:self.userC.identity
  113. accessLevel:RLMSyncAccessLevelRead];
  114. APPLY_PERMISSION(p, admin);
  115. [self waitForSync:adminRealm];
  116. return url;
  117. }
  118. - (void)waitForSync:(RLMRealm *)realm {
  119. [self waitForUploadsForRealm:realm error:nil];
  120. [self waitForDownloadsForRealm:realm error:nil];
  121. [realm refresh];
  122. }
  123. #pragma mark - Permissions
  124. static RLMPermissionRole *getRole(RLMRealm *realm, NSString *roleName) {
  125. return [RLMPermissionRole createOrUpdateInRealm:realm withValue:@{@"name": roleName}];
  126. }
  127. static void addUserToRole(RLMRealm *realm, NSString *roleName, NSString *user) {
  128. [getRole(realm, roleName).users addObject:[RLMPermissionUser userInRealm:realm withIdentity:user]];
  129. }
  130. static void createPermissions(RLMArray<RLMPermission> *permissions) {
  131. auto permission = [RLMPermission permissionForRoleNamed:@"everyone" inArray:permissions];
  132. permission.canCreate = false;
  133. permission.canRead = false;
  134. permission.canQuery = false;
  135. permission.canDelete = false;
  136. permission.canUpdate = false;
  137. permission.canModifySchema = false;
  138. permission.canSetPermissions = false;
  139. permission = [RLMPermission permissionForRoleNamed:@"reader" inArray:permissions];
  140. permission.canRead = true;
  141. permission.canQuery = true;
  142. permission = [RLMPermission permissionForRoleNamed:@"writer" inArray:permissions];
  143. permission.canUpdate = true;
  144. permission.canCreate = true;
  145. permission.canDelete = true;
  146. permission = [RLMPermission permissionForRoleNamed:@"admin" inArray:permissions];
  147. permission.canSetPermissions = true;
  148. }
  149. #define CHECK_REALM_PRIVILEGE(realm, ...) do { \
  150. RLMRealmPrivileges expected{__VA_ARGS__}; \
  151. auto actual = [realm privilegesForRealm]; \
  152. XCTAssertEqual(expected.read, actual.read); \
  153. XCTAssertEqual(expected.update, actual.update); \
  154. XCTAssertEqual(expected.setPermissions, actual.setPermissions); \
  155. XCTAssertEqual(expected.modifySchema, actual.modifySchema); \
  156. } while (0)
  157. #define CHECK_CLASS_PRIVILEGE(realm, ...) do { \
  158. RLMClassPrivileges expected{__VA_ARGS__}; \
  159. auto actual = [realm privilegesForClass:SyncObject.class]; \
  160. XCTAssertEqual(expected.read, actual.read); \
  161. XCTAssertEqual(expected.create, actual.create); \
  162. XCTAssertEqual(expected.update, actual.update); \
  163. XCTAssertEqual(expected.subscribe, actual.subscribe); \
  164. XCTAssertEqual(expected.setPermissions, actual.setPermissions); \
  165. } while (0)
  166. #define CHECK_OBJECT_PRIVILEGE(realm, ...) do { \
  167. RLMObjectPrivileges expected{__VA_ARGS__}; \
  168. auto actual = [realm privilegesForObject:[SyncObject allObjectsInRealm:realm].firstObject]; \
  169. XCTAssertEqual(expected.read, actual.read); \
  170. XCTAssertEqual(expected.del, actual.del); \
  171. XCTAssertEqual(expected.update, actual.update); \
  172. XCTAssertEqual(expected.setPermissions, actual.setPermissions); \
  173. } while (0)
  174. - (void)testRealmReadAccess {
  175. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  176. createPermissions([RLMRealmPermission objectInRealm:realm].permissions);
  177. addUserToRole(realm, @"reader", self.userA.identity);
  178. }];
  179. // userA should now be able to open the Realm and see objects
  180. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  181. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  182. CHECK_REALM_PRIVILEGE(userARealm, .read = true);
  183. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true);
  184. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true);
  185. // userA should not be able to create new objects
  186. CHECK_COUNT(3, SyncObject, userARealm);
  187. [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  188. CHECK_COUNT(6, SyncObject, userARealm);
  189. [self waitForSync:userARealm];
  190. CHECK_COUNT(3, SyncObject, userARealm);
  191. // userB should not be able to read any objects
  192. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  193. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  194. CHECK_REALM_PRIVILEGE(userBRealm, .read = false);
  195. CHECK_CLASS_PRIVILEGE(userBRealm, .read = false);
  196. CHECK_COUNT(0, SyncObject, userBRealm);
  197. }
  198. - (void)testRealmWriteAccess {
  199. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  200. createPermissions([RLMRealmPermission objectInRealm:realm].permissions);
  201. addUserToRole(realm, @"reader", self.userA.identity);
  202. addUserToRole(realm, @"writer", self.userA.identity);
  203. addUserToRole(realm, @"reader", self.userB.identity);
  204. }];
  205. // userA should be able to add objects
  206. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  207. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  208. CHECK_REALM_PRIVILEGE(userARealm, .read = true, .update = true);
  209. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true,
  210. .update = true, .create = true, .setPermissions = true);
  211. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true, .update = true, .del = true, .setPermissions = true);
  212. CHECK_COUNT(3, SyncObject, userARealm);
  213. [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  214. CHECK_COUNT(6, SyncObject, userARealm);
  215. [self waitForSync:userARealm];
  216. CHECK_COUNT(6, SyncObject, userARealm);
  217. // userB's insertions should be reverted
  218. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  219. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  220. CHECK_REALM_PRIVILEGE(userBRealm, .read = true);
  221. CHECK_CLASS_PRIVILEGE(userBRealm, .read = true, .subscribe = true);
  222. CHECK_OBJECT_PRIVILEGE(userBRealm, .read = true);
  223. CHECK_COUNT(6, SyncObject, userBRealm);
  224. [self addSyncObjectsToRealm:userBRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  225. CHECK_COUNT(9, SyncObject, userBRealm);
  226. [self waitForSync:userBRealm];
  227. CHECK_COUNT(6, SyncObject, userBRealm);
  228. }
  229. - (void)testRealmManagePermissions {
  230. // FIXME: this test is wrong; setPermission doesn't govern adding users to roles
  231. #if 0
  232. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  233. createPermissions([RLMRealmPermission objectInRealm:realm].permissions);
  234. addUserToRole(realm, @"reader", self.userA.identity);
  235. addUserToRole(realm, @"writer", self.userA.identity);
  236. addUserToRole(realm, @"admin", self.userA.identity);
  237. addUserToRole(realm, @"reader", self.userB.identity);
  238. addUserToRole(realm, @"writer", self.userB.identity);
  239. addUserToRole(realm, @"reader", self.userC.identity);
  240. }];
  241. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  242. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  243. RLMRealm *userCRealm = [self openRealmForURL:url user:self.userC];
  244. // userC should initially not be able to write to the Realm
  245. [self subscribeToRealm:userCRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  246. CHECK_REALM_PRIVILEGE(userCRealm, .read = true);
  247. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true);
  248. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true);
  249. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  250. [self waitForSync:userCRealm];
  251. CHECK_COUNT(3, SyncObject, userCRealm);
  252. // userB should not be able to grant write permissions to userC
  253. [userBRealm transactionWithBlock:^{
  254. addUserToRole(userBRealm, @"writer", self.userC.identity);
  255. }];
  256. [self waitForSync:userBRealm];
  257. [self waitForSync:userCRealm];
  258. CHECK_REALM_PRIVILEGE(userCRealm, .read = true);
  259. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true);
  260. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true);
  261. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  262. [self waitForSync:userCRealm];
  263. CHECK_COUNT(3, SyncObject, userCRealm);
  264. // userA should be able to grant write permissions to userC
  265. [userARealm transactionWithBlock:^{
  266. addUserToRole(userARealm, @"writer", self.userC.identity);
  267. }];
  268. [self waitForSync:userARealm];
  269. [self waitForSync:userCRealm];
  270. CHECK_REALM_PRIVILEGE(userCRealm, .read = true, .update = true);
  271. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true, .update = true, .create = true);
  272. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true, .update = true, .del = true);
  273. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  274. [self waitForSync:userCRealm];
  275. CHECK_COUNT(6, SyncObject, userCRealm);
  276. #endif
  277. }
  278. - (void)testRealmModifySchema {
  279. // awkward to test due to that reverts will normally crash
  280. // probably need to spawn a child process?
  281. }
  282. - (void)testClassRead {
  283. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  284. createPermissions([RLMClassPermission objectInRealm:realm forClass:SyncObject.class].permissions);
  285. addUserToRole(realm, @"reader", self.userA.identity);
  286. }];
  287. // userA should now be able to open the Realm and see objects
  288. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  289. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  290. CHECK_REALM_PRIVILEGE(userARealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  291. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true);
  292. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true);
  293. CHECK_COUNT(3, SyncObject, userARealm);
  294. // userA should not be able to create new objects
  295. [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  296. CHECK_COUNT(6, SyncObject, userARealm);
  297. [self waitForSync:userARealm];
  298. CHECK_COUNT(3, SyncObject, userARealm);
  299. // userB should not be able to read any objects
  300. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  301. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  302. CHECK_REALM_PRIVILEGE(userBRealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  303. CHECK_CLASS_PRIVILEGE(userBRealm, .read = false);
  304. CHECK_COUNT(0, SyncObject, userBRealm);
  305. }
  306. - (void)testClassUpdate {
  307. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  308. createPermissions([RLMClassPermission objectInRealm:realm forClass:SyncObject.class].permissions);
  309. addUserToRole(realm, @"reader", self.userA.identity);
  310. addUserToRole(realm, @"writer", self.userA.identity);
  311. addUserToRole(realm, @"reader", self.userB.identity);
  312. }];
  313. // userA should be able to mutate objects
  314. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  315. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  316. CHECK_REALM_PRIVILEGE(userARealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  317. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true, .update = true, .create = true);
  318. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true, .update = true, .del = true, .setPermissions = true);
  319. SyncObject *objA = [SyncObject allObjectsInRealm:userARealm].firstObject;
  320. [userARealm transactionWithBlock:^{
  321. objA.stringProp = @"new value";
  322. }];
  323. [self waitForSync:userARealm];
  324. XCTAssertEqualObjects(objA.stringProp, @"new value");
  325. // userB's mutations should be reverted
  326. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  327. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  328. CHECK_REALM_PRIVILEGE(userBRealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  329. CHECK_CLASS_PRIVILEGE(userBRealm, .read = true, .subscribe = true);
  330. CHECK_OBJECT_PRIVILEGE(userBRealm, .read = true);
  331. SyncObject *objB = [SyncObject allObjectsInRealm:userBRealm].firstObject;
  332. [userBRealm transactionWithBlock:^{
  333. objB.stringProp = @"new value 2";
  334. }];
  335. XCTAssertEqualObjects(objB.stringProp, @"new value 2");
  336. [self waitForSync:userBRealm];
  337. XCTAssertEqualObjects(objB.stringProp, @"new value");
  338. }
  339. - (void)testClassCreate {
  340. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  341. createPermissions([RLMClassPermission objectInRealm:realm forClass:SyncObject.class].permissions);
  342. addUserToRole(realm, @"reader", self.userA.identity);
  343. addUserToRole(realm, @"writer", self.userA.identity);
  344. addUserToRole(realm, @"reader", self.userB.identity);
  345. }];
  346. // userA should be able to add objects
  347. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  348. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  349. CHECK_REALM_PRIVILEGE(userARealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  350. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true, .update = true, .create = true);
  351. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true, .update = true, .del = true, .setPermissions = true);
  352. CHECK_COUNT(3, SyncObject, userARealm);
  353. [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  354. CHECK_COUNT(6, SyncObject, userARealm);
  355. [self waitForSync:userARealm];
  356. CHECK_COUNT(6, SyncObject, userARealm);
  357. // userB's insertions should be reverted
  358. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  359. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  360. CHECK_REALM_PRIVILEGE(userBRealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  361. CHECK_CLASS_PRIVILEGE(userBRealm, .read = true, .subscribe = true);
  362. CHECK_OBJECT_PRIVILEGE(userBRealm, .read = true);
  363. CHECK_COUNT(6, SyncObject, userBRealm);
  364. [self addSyncObjectsToRealm:userBRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  365. CHECK_COUNT(9, SyncObject, userBRealm);
  366. [self waitForSync:userBRealm];
  367. CHECK_COUNT(6, SyncObject, userBRealm);
  368. }
  369. - (void)testClassSetPermissions {
  370. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  371. createPermissions([RLMClassPermission objectInRealm:realm forClass:SyncObject.class].permissions);
  372. addUserToRole(realm, @"reader", self.userA.identity);
  373. addUserToRole(realm, @"writer", self.userA.identity);
  374. addUserToRole(realm, @"admin", self.userA.identity);
  375. addUserToRole(realm, @"reader", self.userB.identity);
  376. addUserToRole(realm, @"writer", self.userB.identity);
  377. addUserToRole(realm, @"reader", self.userC.identity);
  378. }];
  379. // Despite having write access userB should not be able to add "update" access to "reader"
  380. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  381. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  382. [userBRealm transactionWithBlock:^{
  383. auto permission = [RLMPermission permissionForRoleNamed:@"reader" onClass:SyncObject.class realm:userBRealm];
  384. permission.canCreate = true;
  385. permission.canUpdate = true;
  386. }];
  387. [self waitForSync:userBRealm];
  388. // userC should be unable to create objects
  389. RLMRealm *userCRealm = [self openRealmForURL:url user:self.userC];
  390. [self subscribeToRealm:userCRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  391. CHECK_REALM_PRIVILEGE(userCRealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  392. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true);
  393. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true);
  394. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  395. CHECK_COUNT(6, SyncObject, userCRealm);
  396. [self waitForSync:userCRealm];
  397. CHECK_COUNT(3, SyncObject, userCRealm);
  398. // userA should able to add "update" access to "reader"
  399. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  400. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  401. [userARealm transactionWithBlock:^{
  402. auto permission = [RLMPermission permissionForRoleNamed:@"reader" onClass:SyncObject.class realm:userARealm];
  403. permission.canCreate = true;
  404. permission.canUpdate = true;
  405. }];
  406. [self waitForSync:userARealm];
  407. // userC should now be able to create objects
  408. [self waitForSync:userCRealm];
  409. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true, .update = true, .create = true);
  410. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true, .update = true, .del = true, .setPermissions = true);
  411. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  412. CHECK_COUNT(6, SyncObject, userCRealm);
  413. [self waitForSync:userCRealm];
  414. CHECK_COUNT(6, SyncObject, userCRealm);
  415. }
  416. - (void)testObjectRead {
  417. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  418. addUserToRole(realm, @"reader", self.userA.identity);
  419. auto obj1 = [ObjectWithPermissions createInRealm:realm withValue:@[@1]];
  420. createPermissions(obj1.permissions);
  421. [ObjectWithPermissions createInRealm:realm withValue:@[@2]];
  422. }];
  423. // userA should be able to see both objects
  424. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  425. [self subscribeToRealm:userARealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  426. CHECK_COUNT(1, ObjectWithPermissions, userARealm);
  427. // userB should not be able to read any objects
  428. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  429. [self subscribeToRealm:userBRealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  430. CHECK_COUNT(0, ObjectWithPermissions, userBRealm);
  431. }
  432. - (void)testObjectTransitiveRead {
  433. }
  434. - (void)testObjectUpdate {
  435. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  436. addUserToRole(realm, @"reader", self.userA.identity);
  437. addUserToRole(realm, @"reader", self.userB.identity);
  438. addUserToRole(realm, @"writer", self.userB.identity);
  439. auto obj1 = [ObjectWithPermissions createInRealm:realm withValue:@[@1]];
  440. createPermissions(obj1.permissions);
  441. }];
  442. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  443. [self subscribeToRealm:userARealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  444. ObjectWithPermissions *objA = [ObjectWithPermissions allObjectsInRealm:userARealm].firstObject;
  445. [userARealm transactionWithBlock:^{
  446. objA.value = 3;
  447. }];
  448. [self waitForSync:userARealm];
  449. XCTAssertEqual(objA.value, 1);
  450. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  451. [self subscribeToRealm:userBRealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  452. ObjectWithPermissions *objB = [ObjectWithPermissions allObjectsInRealm:userBRealm].firstObject;
  453. [userBRealm transactionWithBlock:^{
  454. objB.value = 3;
  455. }];
  456. [self waitForSync:userBRealm];
  457. [self waitForSync:userARealm];
  458. XCTAssertEqual(objA.value, 3);
  459. XCTAssertEqual(objB.value, 3);
  460. }
  461. - (void)testObjectDelete {
  462. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  463. addUserToRole(realm, @"reader", self.userA.identity);
  464. addUserToRole(realm, @"reader", self.userB.identity);
  465. addUserToRole(realm, @"writer", self.userB.identity);
  466. auto obj1 = [ObjectWithPermissions createInRealm:realm withValue:@[@1]];
  467. createPermissions(obj1.permissions);
  468. }];
  469. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  470. [self subscribeToRealm:userARealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  471. ObjectWithPermissions *objA = [ObjectWithPermissions allObjectsInRealm:userARealm].firstObject;
  472. [userARealm transactionWithBlock:^{
  473. [userARealm deleteObject:objA];
  474. }];
  475. CHECK_COUNT(0, ObjectWithPermissions, userARealm);
  476. [self waitForSync:userARealm];
  477. CHECK_COUNT(1, ObjectWithPermissions, userARealm);
  478. objA = [ObjectWithPermissions allObjectsInRealm:userARealm].firstObject;
  479. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  480. [self subscribeToRealm:userBRealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  481. ObjectWithPermissions *objB = [ObjectWithPermissions allObjectsInRealm:userBRealm].firstObject;
  482. [userBRealm transactionWithBlock:^{
  483. [userBRealm deleteObject:objB];
  484. }];
  485. [self waitForSync:userBRealm];
  486. [self waitForSync:userARealm];
  487. CHECK_COUNT(0, ObjectWithPermissions, userARealm);
  488. CHECK_COUNT(0, ObjectWithPermissions, userBRealm);
  489. XCTAssertTrue(objA.invalidated);
  490. XCTAssertTrue(objB.invalidated);
  491. }
  492. - (void)testObjectSetPermissions {
  493. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *) {}];
  494. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  495. [self subscribeToRealm:userARealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  496. [userARealm transactionWithBlock:^{
  497. auto obj = [ObjectWithPermissions createInRealm:userARealm withValue:@[@1]];
  498. auto permissions = [RLMPermission permissionForRoleNamed:@"foo" onObject:obj];
  499. permissions.canRead = true;
  500. addUserToRole(userARealm, @"foo", self.userB.identity);
  501. }];
  502. CHECK_COUNT(1, ObjectWithPermissions, userARealm);
  503. [self waitForSync:userARealm];
  504. CHECK_COUNT(0, ObjectWithPermissions, userARealm);
  505. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  506. [self subscribeToRealm:userBRealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  507. CHECK_COUNT(1, ObjectWithPermissions, userBRealm);
  508. }
  509. - (void)testRetrieveClassPermissionsForRenamedClass {
  510. [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  511. XCTAssertNotNil([RLMClassPermission objectInRealm:realm forClass:RLMPermissionRole.class]);
  512. }];
  513. }
  514. @end