You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
253 lines
10 KiB
253 lines
10 KiB
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright 2018 Realm Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
import XCTest
|
|
import RealmSwift
|
|
|
|
final class PermissionUser: Object {
|
|
// A class with a name that conflicts with an Object class from RealmSwift to verify
|
|
// that it doesn't break anything
|
|
}
|
|
|
|
class SwiftPermissionsAPITests: SwiftSyncTestCase {
|
|
var userA: SyncUser!
|
|
var userB: SyncUser!
|
|
var userC: SyncUser!
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
let baseName = UUID().uuidString
|
|
userA = try! synchronouslyLogInUser(for: .usernamePassword(username: baseName + "-a", password: "a", register: true),
|
|
server: SwiftSyncTestCase.authServerURL())
|
|
userB = try! synchronouslyLogInUser(for: .usernamePassword(username: baseName + "-b", password: "a", register: true),
|
|
server: SwiftSyncTestCase.authServerURL())
|
|
userC = try! synchronouslyLogInUser(for: .usernamePassword(username: baseName + "-c", password: "a", register: true),
|
|
server: SwiftSyncTestCase.authServerURL())
|
|
}
|
|
|
|
override func tearDown() {
|
|
userA.logOut()
|
|
userB.logOut()
|
|
userC.logOut()
|
|
super.tearDown()
|
|
}
|
|
|
|
// MARK: Helper functions
|
|
|
|
func openRealm(_ url: URL, _ user: SyncUser) -> Realm {
|
|
let realm = try! Realm(configuration: user.configuration(realmURL: url))
|
|
waitForSync(realm)
|
|
return realm
|
|
}
|
|
|
|
func subscribe<T: Object>(realm: Realm, type: T.Type, _ filter: String = "TRUEPREDICATE") {
|
|
let ex = expectation(description: "Add partial sync query")
|
|
realm.subscribe(to: type, where: filter) { _, err in
|
|
if let err = err {
|
|
XCTFail("Partial sync subsription failed: \(err)")
|
|
} else {
|
|
ex.fulfill()
|
|
}
|
|
}
|
|
waitForExpectations(timeout: 2.0, handler: nil)
|
|
}
|
|
|
|
func waitForSync(_ realm: Realm) {
|
|
waitForUploads(for: realm)
|
|
waitForDownloads(for: realm)
|
|
realm.refresh()
|
|
}
|
|
|
|
func createRealm(name: String, permissions: (Realm) -> Void) -> URL {
|
|
// Create a new Realm with an admin user
|
|
let admin = createAdminUser(for: SwiftSyncTestCase.authServerURL(),
|
|
username: UUID().uuidString + "-admin")
|
|
let url = URL(string: "realm://127.0.0.1:9080/\(name)")!
|
|
let adminRealm = openRealm(url, admin)
|
|
// FIXME: we currently need to add a subscription to get the permissions types sent to us
|
|
subscribe(realm: adminRealm, type: SwiftSyncObject.self)
|
|
|
|
// Set up permissions on the Realm
|
|
try! adminRealm.write {
|
|
adminRealm.create(SwiftSyncObject.self, value: ["obj 1"])
|
|
permissions(adminRealm)
|
|
}
|
|
|
|
// FIXME: we currently need to also add the old realm-level permissions
|
|
let ex1 = expectation(description: "Setting a permission should work.")
|
|
let ex2 = expectation(description: "Setting a permission should work.")
|
|
let ex3 = expectation(description: "Setting a permission should work.")
|
|
admin.apply(SyncPermission(realmPath: url.path, identity: userA.identity!, accessLevel: .read)) { error in
|
|
XCTAssertNil(error)
|
|
ex1.fulfill()
|
|
}
|
|
admin.apply(SyncPermission(realmPath: url.path, identity: userB.identity!, accessLevel: .read)) { error in
|
|
XCTAssertNil(error)
|
|
ex2.fulfill()
|
|
}
|
|
admin.apply(SyncPermission(realmPath: url.path, identity: userC.identity!, accessLevel: .read)) { error in
|
|
XCTAssertNil(error)
|
|
ex3.fulfill()
|
|
}
|
|
waitForExpectations(timeout: 2.0, handler: nil)
|
|
waitForSync(adminRealm)
|
|
|
|
return url
|
|
}
|
|
|
|
func createDefaultPermisisons(_ permissions: List<Permission>) {
|
|
var p = permissions.findOrCreate(forRoleNamed: "everyone")
|
|
p.canCreate = false
|
|
p.canRead = false
|
|
p.canQuery = false
|
|
p.canDelete = false
|
|
p.canUpdate = false
|
|
p.canModifySchema = false
|
|
p.canSetPermissions = false
|
|
|
|
p = permissions.findOrCreate(forRoleNamed: "reader")
|
|
p.canRead = true
|
|
p.canQuery = true
|
|
|
|
p = permissions.findOrCreate(forRoleNamed: "writer")
|
|
p.canUpdate = true
|
|
p.canCreate = true
|
|
p.canDelete = true
|
|
|
|
p = permissions.findOrCreate(forRoleNamed: "admin")
|
|
p.canSetPermissions = true
|
|
}
|
|
|
|
func add(user: SyncUser, toRole roleName: String, inRealm realm: Realm) {
|
|
let user = realm.create(RealmSwift.PermissionUser.self, value: [user.identity!], update: true)
|
|
realm.create(PermissionRole.self, value: [roleName], update: true).users.append(user)
|
|
}
|
|
|
|
|
|
// MARK: Tests
|
|
|
|
func testRealmRead() {
|
|
let url = createRealm(name: "testRealmRead") { realm in
|
|
createDefaultPermisisons(realm.permissions)
|
|
add(user: userA, toRole: "reader", inRealm: realm)
|
|
}
|
|
|
|
// userA should now be able to open the Realm and see objects
|
|
let realmA = openRealm(url, userA)
|
|
subscribe(realm: realmA, type: SwiftSyncObject.self)
|
|
XCTAssertEqual(realmA.getPrivileges(), [.read])
|
|
XCTAssertEqual(realmA.getPrivileges(SwiftSyncObject.self), [.read, .subscribe])
|
|
XCTAssertEqual(realmA.getPrivileges(realmA.objects(SwiftSyncObject.self).first!), [.read])
|
|
|
|
// userA should not be able to create new objects
|
|
XCTAssertEqual(realmA.objects(SwiftSyncObject.self).count, 1)
|
|
try! realmA.write {
|
|
realmA.create(SwiftSyncObject.self, value: ["obj 2"])
|
|
}
|
|
XCTAssertEqual(realmA.objects(SwiftSyncObject.self).count, 2)
|
|
waitForSync(realmA)
|
|
XCTAssertEqual(realmA.objects(SwiftSyncObject.self).count, 1)
|
|
|
|
// userB should not be able to read any objects
|
|
let realmB = openRealm(url, userB)
|
|
subscribe(realm: realmB, type: SwiftSyncObject.self)
|
|
XCTAssertEqual(realmB.getPrivileges(), [])
|
|
XCTAssertEqual(realmB.getPrivileges(SwiftSyncObject.self), [])
|
|
XCTAssertEqual(realmB.objects(SwiftSyncObject.self).count, 0)
|
|
}
|
|
|
|
func testRealmWrite() {
|
|
let url = createRealm(name: "testRealmWrite") { realm in
|
|
createDefaultPermisisons(realm.permissions)
|
|
add(user: userA, toRole: "reader", inRealm: realm)
|
|
add(user: userA, toRole: "writer", inRealm: realm)
|
|
add(user: userB, toRole: "reader", inRealm: realm)
|
|
}
|
|
|
|
// userA should now be able to open the Realm and see objects
|
|
let realmA = openRealm(url, userA)
|
|
subscribe(realm: realmA, type: SwiftSyncObject.self)
|
|
XCTAssertEqual(realmA.getPrivileges(), [.read, .update])
|
|
XCTAssertEqual(realmA.getPrivileges(SwiftSyncObject.self),
|
|
[.read, .subscribe, .update, .create, .setPermissions])
|
|
XCTAssertEqual(realmA.getPrivileges(realmA.objects(SwiftSyncObject.self).first!),
|
|
[.read, .update, .delete, .setPermissions])
|
|
|
|
// userA should be able to create new objects
|
|
XCTAssertEqual(realmA.objects(SwiftSyncObject.self).count, 1)
|
|
try! realmA.write {
|
|
realmA.create(SwiftSyncObject.self, value: ["obj 2"])
|
|
}
|
|
XCTAssertEqual(realmA.objects(SwiftSyncObject.self).count, 2)
|
|
waitForSync(realmA)
|
|
XCTAssertEqual(realmA.objects(SwiftSyncObject.self).count, 2)
|
|
|
|
// userB's insertions should be reverted
|
|
let realmB = openRealm(url, userB)
|
|
subscribe(realm: realmB, type: SwiftSyncObject.self)
|
|
XCTAssertEqual(realmB.objects(SwiftSyncObject.self).count, 2)
|
|
try! realmB.write {
|
|
realmB.create(SwiftSyncObject.self, value: ["obj 3"])
|
|
}
|
|
XCTAssertEqual(realmB.objects(SwiftSyncObject.self).count, 3)
|
|
waitForSync(realmB)
|
|
XCTAssertEqual(realmB.objects(SwiftSyncObject.self).count, 2)
|
|
}
|
|
func testRealmSetPermissions() {
|
|
|
|
}
|
|
func testRealmModifySchema() {
|
|
|
|
}
|
|
|
|
func testClassRead() {
|
|
let url = createRealm(name: "testClassRead") { realm in
|
|
createDefaultPermisisons(realm.permissions(forType: SwiftSyncObject.self))
|
|
add(user: userA, toRole: "reader", inRealm: realm)
|
|
}
|
|
|
|
// userA should now be able to open the Realm and see objects
|
|
let realmA = openRealm(url, userA)
|
|
subscribe(realm: realmA, type: SwiftSyncObject.self)
|
|
XCTAssertEqual(realmA.getPrivileges(), [.read, .update, .setPermissions, .modifySchema])
|
|
XCTAssertEqual(realmA.getPrivileges(SwiftSyncObject.self), [.read, .subscribe])
|
|
XCTAssertEqual(realmA.getPrivileges(realmA.objects(SwiftSyncObject.self).first!), [.read])
|
|
|
|
// userA should not be able to create new objects
|
|
XCTAssertEqual(realmA.objects(SwiftSyncObject.self).count, 1)
|
|
try! realmA.write {
|
|
realmA.create(SwiftSyncObject.self, value: ["obj 2"])
|
|
}
|
|
XCTAssertEqual(realmA.objects(SwiftSyncObject.self).count, 2)
|
|
waitForSync(realmA)
|
|
XCTAssertEqual(realmA.objects(SwiftSyncObject.self).count, 1)
|
|
|
|
// userB should not be able to read any objects
|
|
let realmB = openRealm(url, userB)
|
|
subscribe(realm: realmB, type: SwiftSyncObject.self)
|
|
XCTAssertEqual(realmB.getPrivileges(), [.read, .update, .setPermissions, .modifySchema])
|
|
XCTAssertEqual(realmB.getPrivileges(SwiftSyncObject.self), [])
|
|
XCTAssertEqual(realmB.objects(SwiftSyncObject.self).count, 0)
|
|
}
|
|
func testClassWrite() {
|
|
|
|
}
|
|
func testClassSetPermissions() {
|
|
|
|
}
|
|
}
|
|
|