RLMPermissionsTests.mm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  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. __block NSError *error;
  83. XCTestExpectation *ex = [self expectationWithDescription:@"Should be able to successfully complete a query"];
  84. [realm subscribeToObjects:cls where:pred callback:^(__unused RLMResults *results, NSError *err) {
  85. error = err;
  86. [ex fulfill];
  87. }];
  88. [self waitForExpectations:@[ex] timeout:20.0];
  89. return error;
  90. }
  91. - (NSURL *)createRealmWithName:(SEL)sel permissions:(void (^)(RLMRealm *realm))block {
  92. // Create a new Realm with an admin user
  93. RLMSyncUser *admin = [self createAdminUserForURL:[RLMSyncTestCase authServerURL]
  94. username:[[NSUUID UUID] UUIDString]];
  95. auto url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"realm://127.0.0.1:9080/%@", NSStringFromSelector(sel)]];
  96. RLMRealm *adminRealm = [self openRealmForURL:url user:admin];
  97. [self addSyncObjectsToRealm:adminRealm descriptions:@[@"child-1", @"child-2", @"child-3"]];
  98. CHECK_COUNT(3, SyncObject, adminRealm);
  99. [self waitForUploadsForRealm:adminRealm error:nil];
  100. [self waitForDownloadsForRealm:adminRealm error:nil];
  101. // FIXME: we currently need to add a subscription to get the permissions types sent to us
  102. [adminRealm refresh];
  103. CHECK_COUNT(0, SyncObject, adminRealm);
  104. [self subscribeToRealm:adminRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  105. CHECK_COUNT(3, SyncObject, adminRealm);
  106. // Set up permissions on the Realm
  107. [adminRealm transactionWithBlock:^{ block(adminRealm); }];
  108. // FIXME: we currently need to also add the old realm-level permissions
  109. RLMSyncPermission *p = [[RLMSyncPermission alloc] initWithRealmPath:[url path]
  110. identity:self.userA.identity
  111. accessLevel:RLMSyncAccessLevelRead];
  112. APPLY_PERMISSION(p, admin);
  113. p = [[RLMSyncPermission alloc] initWithRealmPath:[url path] identity:self.userB.identity
  114. accessLevel:RLMSyncAccessLevelRead];
  115. APPLY_PERMISSION(p, admin);
  116. p = [[RLMSyncPermission alloc] initWithRealmPath:[url path] identity:self.userC.identity
  117. accessLevel:RLMSyncAccessLevelRead];
  118. APPLY_PERMISSION(p, admin);
  119. [self waitForSync:adminRealm];
  120. return url;
  121. }
  122. - (void)waitForSync:(RLMRealm *)realm {
  123. [self waitForUploadsForRealm:realm error:nil];
  124. [self waitForDownloadsForRealm:realm error:nil];
  125. [realm refresh];
  126. }
  127. #pragma mark - Permissions
  128. static RLMPermissionRole *getRole(RLMRealm *realm, NSString *roleName) {
  129. return [RLMPermissionRole createOrUpdateInRealm:realm withValue:@{@"name": roleName}];
  130. }
  131. static void addUserToRole(RLMRealm *realm, NSString *roleName, NSString *user) {
  132. [getRole(realm, roleName).users addObject:[RLMPermissionUser userInRealm:realm withIdentity:user]];
  133. }
  134. static void createPermissions(RLMArray<RLMPermission> *permissions) {
  135. auto permission = [RLMPermission permissionForRoleNamed:@"everyone" inArray:permissions];
  136. permission.canCreate = false;
  137. permission.canRead = false;
  138. permission.canQuery = false;
  139. permission.canDelete = false;
  140. permission.canUpdate = false;
  141. permission.canModifySchema = false;
  142. permission.canSetPermissions = false;
  143. permission = [RLMPermission permissionForRoleNamed:@"reader" inArray:permissions];
  144. permission.canRead = true;
  145. permission.canQuery = true;
  146. permission = [RLMPermission permissionForRoleNamed:@"writer" inArray:permissions];
  147. permission.canUpdate = true;
  148. permission.canCreate = true;
  149. permission.canDelete = true;
  150. permission = [RLMPermission permissionForRoleNamed:@"admin" inArray:permissions];
  151. permission.canSetPermissions = true;
  152. }
  153. #define CHECK_REALM_PRIVILEGE(realm, ...) do { \
  154. RLMRealmPrivileges expected{__VA_ARGS__}; \
  155. auto actual = [realm privilegesForRealm]; \
  156. XCTAssertEqual(expected.read, actual.read); \
  157. XCTAssertEqual(expected.update, actual.update); \
  158. XCTAssertEqual(expected.setPermissions, actual.setPermissions); \
  159. XCTAssertEqual(expected.modifySchema, actual.modifySchema); \
  160. } while (0)
  161. #define CHECK_CLASS_PRIVILEGE(realm, ...) do { \
  162. RLMClassPrivileges expected{__VA_ARGS__}; \
  163. auto actual = [realm privilegesForClass:SyncObject.class]; \
  164. XCTAssertEqual(expected.read, actual.read); \
  165. XCTAssertEqual(expected.create, actual.create); \
  166. XCTAssertEqual(expected.update, actual.update); \
  167. XCTAssertEqual(expected.subscribe, actual.subscribe); \
  168. XCTAssertEqual(expected.setPermissions, actual.setPermissions); \
  169. } while (0)
  170. #define CHECK_OBJECT_PRIVILEGE(realm, ...) do { \
  171. RLMObjectPrivileges expected{__VA_ARGS__}; \
  172. auto actual = [realm privilegesForObject:[SyncObject allObjectsInRealm:realm].firstObject]; \
  173. XCTAssertEqual(expected.read, actual.read); \
  174. XCTAssertEqual(expected.del, actual.del); \
  175. XCTAssertEqual(expected.update, actual.update); \
  176. XCTAssertEqual(expected.setPermissions, actual.setPermissions); \
  177. } while (0)
  178. - (void)testRealmReadAccess {
  179. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  180. createPermissions([RLMRealmPermission objectInRealm:realm].permissions);
  181. addUserToRole(realm, @"reader", self.userA.identity);
  182. }];
  183. // userA should now be able to open the Realm and see objects
  184. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  185. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  186. CHECK_REALM_PRIVILEGE(userARealm, .read = true);
  187. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true);
  188. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true);
  189. // userA should not be able to create new objects
  190. CHECK_COUNT(3, SyncObject, userARealm);
  191. [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  192. CHECK_COUNT(6, SyncObject, userARealm);
  193. [self waitForSync:userARealm];
  194. CHECK_COUNT(3, SyncObject, userARealm);
  195. // userB should not be able to read any objects
  196. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  197. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  198. CHECK_REALM_PRIVILEGE(userBRealm, .read = false);
  199. CHECK_CLASS_PRIVILEGE(userBRealm, .read = false);
  200. CHECK_COUNT(0, SyncObject, userBRealm);
  201. }
  202. - (void)testRealmWriteAccess {
  203. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  204. createPermissions([RLMRealmPermission objectInRealm:realm].permissions);
  205. addUserToRole(realm, @"reader", self.userA.identity);
  206. addUserToRole(realm, @"writer", self.userA.identity);
  207. addUserToRole(realm, @"reader", self.userB.identity);
  208. }];
  209. // userA should be able to add objects
  210. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  211. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  212. CHECK_REALM_PRIVILEGE(userARealm, .read = true, .update = true);
  213. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true,
  214. .update = true, .create = true, .setPermissions = true);
  215. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true, .update = true, .del = true, .setPermissions = true);
  216. CHECK_COUNT(3, SyncObject, userARealm);
  217. [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  218. CHECK_COUNT(6, SyncObject, userARealm);
  219. [self waitForSync:userARealm];
  220. CHECK_COUNT(6, SyncObject, userARealm);
  221. // userB's insertions should be reverted
  222. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  223. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  224. CHECK_REALM_PRIVILEGE(userBRealm, .read = true);
  225. CHECK_CLASS_PRIVILEGE(userBRealm, .read = true, .subscribe = true);
  226. CHECK_OBJECT_PRIVILEGE(userBRealm, .read = true);
  227. CHECK_COUNT(6, SyncObject, userBRealm);
  228. [self addSyncObjectsToRealm:userBRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  229. CHECK_COUNT(9, SyncObject, userBRealm);
  230. [self waitForSync:userBRealm];
  231. CHECK_COUNT(6, SyncObject, userBRealm);
  232. }
  233. - (void)testRealmManagePermissions {
  234. // FIXME: this test is wrong; setPermission doesn't govern adding users to roles
  235. #if 0
  236. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  237. createPermissions([RLMRealmPermission objectInRealm:realm].permissions);
  238. addUserToRole(realm, @"reader", self.userA.identity);
  239. addUserToRole(realm, @"writer", self.userA.identity);
  240. addUserToRole(realm, @"admin", self.userA.identity);
  241. addUserToRole(realm, @"reader", self.userB.identity);
  242. addUserToRole(realm, @"writer", self.userB.identity);
  243. addUserToRole(realm, @"reader", self.userC.identity);
  244. }];
  245. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  246. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  247. RLMRealm *userCRealm = [self openRealmForURL:url user:self.userC];
  248. // userC should initially not be able to write to the Realm
  249. [self subscribeToRealm:userCRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  250. CHECK_REALM_PRIVILEGE(userCRealm, .read = true);
  251. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true);
  252. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true);
  253. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  254. [self waitForSync:userCRealm];
  255. CHECK_COUNT(3, SyncObject, userCRealm);
  256. // userB should not be able to grant write permissions to userC
  257. [userBRealm transactionWithBlock:^{
  258. addUserToRole(userBRealm, @"writer", self.userC.identity);
  259. }];
  260. [self waitForSync:userBRealm];
  261. [self waitForSync:userCRealm];
  262. CHECK_REALM_PRIVILEGE(userCRealm, .read = true);
  263. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true);
  264. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true);
  265. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  266. [self waitForSync:userCRealm];
  267. CHECK_COUNT(3, SyncObject, userCRealm);
  268. // userA should be able to grant write permissions to userC
  269. [userARealm transactionWithBlock:^{
  270. addUserToRole(userARealm, @"writer", self.userC.identity);
  271. }];
  272. [self waitForSync:userARealm];
  273. [self waitForSync:userCRealm];
  274. CHECK_REALM_PRIVILEGE(userCRealm, .read = true, .update = true);
  275. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true, .update = true, .create = true);
  276. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true, .update = true, .del = true);
  277. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  278. [self waitForSync:userCRealm];
  279. CHECK_COUNT(6, SyncObject, userCRealm);
  280. #endif
  281. }
  282. - (void)testRealmModifySchema {
  283. // awkward to test due to that reverts will normally crash
  284. // probably need to spawn a child process?
  285. }
  286. - (void)testClassRead {
  287. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  288. createPermissions([RLMClassPermission objectInRealm:realm forClass:SyncObject.class].permissions);
  289. addUserToRole(realm, @"reader", self.userA.identity);
  290. }];
  291. // userA should now be able to open the Realm and see objects
  292. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  293. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  294. CHECK_REALM_PRIVILEGE(userARealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  295. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true);
  296. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true);
  297. CHECK_COUNT(3, SyncObject, userARealm);
  298. // userA should not be able to create new objects
  299. [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  300. CHECK_COUNT(6, SyncObject, userARealm);
  301. [self waitForSync:userARealm];
  302. CHECK_COUNT(3, SyncObject, userARealm);
  303. // userB should not be able to read any objects
  304. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  305. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  306. CHECK_REALM_PRIVILEGE(userBRealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  307. CHECK_CLASS_PRIVILEGE(userBRealm, .read = false);
  308. CHECK_COUNT(0, SyncObject, userBRealm);
  309. }
  310. - (void)testClassUpdate {
  311. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  312. createPermissions([RLMClassPermission objectInRealm:realm forClass:SyncObject.class].permissions);
  313. addUserToRole(realm, @"reader", self.userA.identity);
  314. addUserToRole(realm, @"writer", self.userA.identity);
  315. addUserToRole(realm, @"reader", self.userB.identity);
  316. }];
  317. // userA should be able to mutate objects
  318. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  319. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  320. CHECK_REALM_PRIVILEGE(userARealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  321. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true, .update = true, .create = true);
  322. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true, .update = true, .del = true, .setPermissions = true);
  323. SyncObject *objA = [SyncObject allObjectsInRealm:userARealm].firstObject;
  324. [userARealm transactionWithBlock:^{
  325. objA.stringProp = @"new value";
  326. }];
  327. [self waitForSync:userARealm];
  328. XCTAssertEqualObjects(objA.stringProp, @"new value");
  329. // userB's mutations should be reverted
  330. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  331. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  332. CHECK_REALM_PRIVILEGE(userBRealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  333. CHECK_CLASS_PRIVILEGE(userBRealm, .read = true, .subscribe = true);
  334. CHECK_OBJECT_PRIVILEGE(userBRealm, .read = true);
  335. SyncObject *objB = [SyncObject allObjectsInRealm:userBRealm].firstObject;
  336. [userBRealm transactionWithBlock:^{
  337. objB.stringProp = @"new value 2";
  338. }];
  339. XCTAssertEqualObjects(objB.stringProp, @"new value 2");
  340. [self waitForSync:userBRealm];
  341. XCTAssertEqualObjects(objB.stringProp, @"new value");
  342. }
  343. - (void)testClassCreate {
  344. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  345. createPermissions([RLMClassPermission objectInRealm:realm forClass:SyncObject.class].permissions);
  346. addUserToRole(realm, @"reader", self.userA.identity);
  347. addUserToRole(realm, @"writer", self.userA.identity);
  348. addUserToRole(realm, @"reader", self.userB.identity);
  349. }];
  350. // userA should be able to add objects
  351. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  352. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  353. CHECK_REALM_PRIVILEGE(userARealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  354. CHECK_CLASS_PRIVILEGE(userARealm, .read = true, .subscribe = true, .update = true, .create = true);
  355. CHECK_OBJECT_PRIVILEGE(userARealm, .read = true, .update = true, .del = true, .setPermissions = true);
  356. CHECK_COUNT(3, SyncObject, userARealm);
  357. [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  358. CHECK_COUNT(6, SyncObject, userARealm);
  359. [self waitForSync:userARealm];
  360. CHECK_COUNT(6, SyncObject, userARealm);
  361. // userB's insertions should be reverted
  362. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  363. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  364. CHECK_REALM_PRIVILEGE(userBRealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  365. CHECK_CLASS_PRIVILEGE(userBRealm, .read = true, .subscribe = true);
  366. CHECK_OBJECT_PRIVILEGE(userBRealm, .read = true);
  367. CHECK_COUNT(6, SyncObject, userBRealm);
  368. [self addSyncObjectsToRealm:userBRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  369. CHECK_COUNT(9, SyncObject, userBRealm);
  370. [self waitForSync:userBRealm];
  371. CHECK_COUNT(6, SyncObject, userBRealm);
  372. }
  373. - (void)testClassSetPermissions {
  374. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  375. createPermissions([RLMClassPermission objectInRealm:realm forClass:SyncObject.class].permissions);
  376. addUserToRole(realm, @"reader", self.userA.identity);
  377. addUserToRole(realm, @"writer", self.userA.identity);
  378. addUserToRole(realm, @"admin", self.userA.identity);
  379. addUserToRole(realm, @"reader", self.userB.identity);
  380. addUserToRole(realm, @"writer", self.userB.identity);
  381. addUserToRole(realm, @"reader", self.userC.identity);
  382. }];
  383. // Despite having write access userB should not be able to add "update" access to "reader"
  384. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  385. [self subscribeToRealm:userBRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  386. [userBRealm transactionWithBlock:^{
  387. auto permission = [RLMPermission permissionForRoleNamed:@"reader" onClass:SyncObject.class realm:userBRealm];
  388. permission.canCreate = true;
  389. permission.canUpdate = true;
  390. }];
  391. [self waitForSync:userBRealm];
  392. // userC should be unable to create objects
  393. RLMRealm *userCRealm = [self openRealmForURL:url user:self.userC];
  394. [self subscribeToRealm:userCRealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  395. CHECK_REALM_PRIVILEGE(userCRealm, .read = true, .update = true, .setPermissions = true, .modifySchema = true);
  396. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true);
  397. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true);
  398. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  399. CHECK_COUNT(6, SyncObject, userCRealm);
  400. [self waitForSync:userCRealm];
  401. CHECK_COUNT(3, SyncObject, userCRealm);
  402. // userA should able to add "update" access to "reader"
  403. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  404. [self subscribeToRealm:userARealm type:[SyncObject class] where:@"TRUEPREDICATE"];
  405. [userARealm transactionWithBlock:^{
  406. auto permission = [RLMPermission permissionForRoleNamed:@"reader" onClass:SyncObject.class realm:userARealm];
  407. permission.canCreate = true;
  408. permission.canUpdate = true;
  409. }];
  410. [self waitForSync:userARealm];
  411. // userC should now be able to create objects
  412. [self waitForSync:userCRealm];
  413. CHECK_CLASS_PRIVILEGE(userCRealm, .read = true, .subscribe = true, .update = true, .create = true);
  414. CHECK_OBJECT_PRIVILEGE(userCRealm, .read = true, .update = true, .del = true, .setPermissions = true);
  415. [self addSyncObjectsToRealm:userCRealm descriptions:@[@"child-4", @"child-5", @"child-6"]];
  416. CHECK_COUNT(6, SyncObject, userCRealm);
  417. [self waitForSync:userCRealm];
  418. CHECK_COUNT(6, SyncObject, userCRealm);
  419. }
  420. - (void)testObjectRead {
  421. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  422. addUserToRole(realm, @"reader", self.userA.identity);
  423. auto obj1 = [ObjectWithPermissions createInRealm:realm withValue:@[@1]];
  424. createPermissions(obj1.permissions);
  425. [ObjectWithPermissions createInRealm:realm withValue:@[@2]];
  426. }];
  427. // userA should be able to see both objects
  428. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  429. [self subscribeToRealm:userARealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  430. CHECK_COUNT(1, ObjectWithPermissions, userARealm);
  431. // userB should not be able to read any objects
  432. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  433. [self subscribeToRealm:userBRealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  434. CHECK_COUNT(0, ObjectWithPermissions, userBRealm);
  435. }
  436. - (void)testObjectTransitiveRead {
  437. }
  438. - (void)testObjectUpdate {
  439. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  440. addUserToRole(realm, @"reader", self.userA.identity);
  441. addUserToRole(realm, @"reader", self.userB.identity);
  442. addUserToRole(realm, @"writer", self.userB.identity);
  443. auto obj1 = [ObjectWithPermissions createInRealm:realm withValue:@[@1]];
  444. createPermissions(obj1.permissions);
  445. }];
  446. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  447. [self subscribeToRealm:userARealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  448. ObjectWithPermissions *objA = [ObjectWithPermissions allObjectsInRealm:userARealm].firstObject;
  449. [userARealm transactionWithBlock:^{
  450. objA.value = 3;
  451. }];
  452. [self waitForSync:userARealm];
  453. XCTAssertEqual(objA.value, 1);
  454. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  455. [self subscribeToRealm:userBRealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  456. ObjectWithPermissions *objB = [ObjectWithPermissions allObjectsInRealm:userBRealm].firstObject;
  457. [userBRealm transactionWithBlock:^{
  458. objB.value = 3;
  459. }];
  460. [self waitForSync:userBRealm];
  461. [self waitForSync:userARealm];
  462. XCTAssertEqual(objA.value, 3);
  463. XCTAssertEqual(objB.value, 3);
  464. }
  465. - (void)testObjectDelete {
  466. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  467. addUserToRole(realm, @"reader", self.userA.identity);
  468. addUserToRole(realm, @"reader", self.userB.identity);
  469. addUserToRole(realm, @"writer", self.userB.identity);
  470. auto obj1 = [ObjectWithPermissions createInRealm:realm withValue:@[@1]];
  471. createPermissions(obj1.permissions);
  472. }];
  473. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  474. [self subscribeToRealm:userARealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  475. ObjectWithPermissions *objA = [ObjectWithPermissions allObjectsInRealm:userARealm].firstObject;
  476. [userARealm transactionWithBlock:^{
  477. [userARealm deleteObject:objA];
  478. }];
  479. CHECK_COUNT(0, ObjectWithPermissions, userARealm);
  480. [self waitForSync:userARealm];
  481. CHECK_COUNT(1, ObjectWithPermissions, userARealm);
  482. objA = [ObjectWithPermissions allObjectsInRealm:userARealm].firstObject;
  483. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  484. [self subscribeToRealm:userBRealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  485. ObjectWithPermissions *objB = [ObjectWithPermissions allObjectsInRealm:userBRealm].firstObject;
  486. [userBRealm transactionWithBlock:^{
  487. [userBRealm deleteObject:objB];
  488. }];
  489. [self waitForSync:userBRealm];
  490. [self waitForSync:userARealm];
  491. CHECK_COUNT(0, ObjectWithPermissions, userARealm);
  492. CHECK_COUNT(0, ObjectWithPermissions, userBRealm);
  493. XCTAssertTrue(objA.invalidated);
  494. XCTAssertTrue(objB.invalidated);
  495. }
  496. - (void)testObjectSetPermissions {
  497. NSURL *url = [self createRealmWithName:_cmd permissions:^(RLMRealm *) {}];
  498. RLMRealm *userARealm = [self openRealmForURL:url user:self.userA];
  499. [self subscribeToRealm:userARealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  500. [userARealm transactionWithBlock:^{
  501. auto obj = [ObjectWithPermissions createInRealm:userARealm withValue:@[@1]];
  502. auto permissions = [RLMPermission permissionForRoleNamed:@"foo" onObject:obj];
  503. permissions.canRead = true;
  504. addUserToRole(userARealm, @"foo", self.userB.identity);
  505. }];
  506. CHECK_COUNT(1, ObjectWithPermissions, userARealm);
  507. [self waitForSync:userARealm];
  508. CHECK_COUNT(0, ObjectWithPermissions, userARealm);
  509. RLMRealm *userBRealm = [self openRealmForURL:url user:self.userB];
  510. [self subscribeToRealm:userBRealm type:[ObjectWithPermissions class] where:@"TRUEPREDICATE"];
  511. CHECK_COUNT(1, ObjectWithPermissions, userBRealm);
  512. }
  513. - (void)testRetrieveClassPermissionsForRenamedClass {
  514. [self createRealmWithName:_cmd permissions:^(RLMRealm *realm) {
  515. XCTAssertNotNil([RLMClassPermission objectInRealm:realm forClass:RLMPermissionRole.class]);
  516. }];
  517. }
  518. @end