/* jshint globalstrict:true, strict:true, maxlen: 5000 */ /* global describe, before, after, it, require*/ // ////////////////////////////////////////////////////////////////////////////// // / @brief tests for user access rights // / // / @file // / // / DISCLAIMER // / // / Copyright 2017 ArangoDB GmbH, Cologne, Germany // / // / 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. // / // / Copyright holder is ArangoDB GmbH, Cologne, Germany // / // / @author Michael Hackstein // / @author Mark Vollmary // / @author Copyright 2017, ArangoDB GmbH, Cologne, Germany // ////////////////////////////////////////////////////////////////////////////// 'use strict'; const expect = require('chai').expect; const users = require('@arangodb/users'); const helper = require('@arangodb/user-helper'); const tasks = require('@arangodb/tasks'); const pu = require('@arangodb/process-utils'); const download = require('internal').download; const dbName = helper.dbName; const colName = helper.colName; const rightLevels = helper.rightLevels; const errors = require('@arangodb').errors; const keySpaceId = 'task_collection_level_create_keyspace'; const userSet = helper.userSet; const systemLevel = helper.systemLevel; const dbLevel = helper.dbLevel; const colLevel = helper.colLevel; const arango = require('internal').arango; const db = require('internal').db; for (let l of rightLevels) { systemLevel[l] = new Set(); dbLevel[l] = new Set(); colLevel[l] = new Set(); } const wait = (keySpaceId, key) => { for (let i = 0; i < 200; i++) { if (getKey(keySpaceId, key)) break; require('internal').wait(0.1); } }; const createKeySpace = (keySpaceId) => { return executeJS(`return global.KEYSPACE_CREATE('${keySpaceId}', 128, true);`).body === 'true'; }; const setKeySpace = (keySpaceId, name) => { return executeJS(`global.KEY_SET('${keySpaceId}', '${name}', false);`); }; const dropKeySpace = (keySpaceId) => { executeJS(`global.KEYSPACE_DROP('${keySpaceId}');`); }; const getKey = (keySpaceId, key) => { return executeJS(`return global.KEY_GET('${keySpaceId}', '${key}');`).body === 'true'; }; const executeJS = (code) => { let httpOptions = pu.makeAuthorizationHeaders({ username: 'root', password: '' }); httpOptions.method = 'POST'; httpOptions.timeout = 1800; httpOptions.returnBodyOnError = true; return download(arango.getEndpoint().replace('tcp', 'http') + `/_db/${dbName}/_admin/execute?returnAsJSON=true`, code, httpOptions); }; helper.switchUser('root', '_system'); helper.removeAllUsers(); helper.generateAllUsers(); describe('User Rights Management', () => { it('should check if all users are created', () => { helper.switchUser('root', '_system'); expect(userSet.size).to.be.greaterThan(0); expect(userSet.size).to.equal(helper.userCount); for (let name of userSet) { expect(users.document(name), `Could not find user: ${name}`).to.not.be.undefined; } }); it('should test rights for', () => { for (let name of userSet) { let canUse = false; try { helper.switchUser(name, dbName); canUse = true; } catch (e) { canUse = false; } if (canUse) { describe(`user ${name}`, () => { before(() => { helper.switchUser(name, dbName); }); describe('update on collection level', () => { const rootTestCollection = (switchBack = true) => { helper.switchUser('root', dbName); let col = db._collection(colName); if (switchBack) { helper.switchUser(name, dbName); } return col !== null; }; const rootTruncateCollection = () => { if (rootTestCollection(false)) { db._collection(colName).truncate({ compact: false }); } helper.switchUser(name, dbName); }; describe('create a document', () => { before(() => { db._useDatabase(dbName); rootTruncateCollection(); dropKeySpace(keySpaceId); expect(createKeySpace(keySpaceId)).to.equal(true, 'keySpace creation failed!'); }); it('by key', () => { expect(rootTestCollection()).to.equal(true, 'Precondition failed, the collection does not exist'); setKeySpace(keySpaceId, name); const taskId = 'task_collection_level_create_by_key' + name; const task = { id: taskId, name: taskId, command: `(function (params) { try { const db = require('@arangodb').db; db._collection('${colName}').save({ _key: '123', foo: 'bar' }); global.KEY_SET('${keySpaceId}', '${name}_status', true); } catch (e) { global.KEY_SET('${keySpaceId}', '${name}_status', false); }finally { global.KEY_SET('${keySpaceId}', '${name}', true); } })(params);` }; if (dbLevel['rw'].has(name)) { if ((dbLevel['rw'].has(name) || dbLevel['ro'].has(name)) && colLevel['rw'].has(name)) { let col = db._collection(colName); try { col.document('123'); expect(false).to.equal(true, 'Precondition failed, document already inserted.'); } catch (e) {} tasks.register(task); wait(keySpaceId, name); expect(getKey(keySpaceId, `${name}_status`)).to.equal(true, `${name} the create did not pass through...`); expect(col.document('123').foo).to.equal('bar', `${name} the create did not pass through...`); } else { let hasReadAccess = ((dbLevel['rw'].has(name) || dbLevel['ro'].has(name)) && (colLevel['rw'].has(name) || colLevel['ro'].has(name))); if (hasReadAccess) { let col = db._collection(colName); try { col.document('123'); expect(false).to.equal(true, 'Precondition failed, document already inserted.'); } catch (e) {} } tasks.register(task); wait(keySpaceId, name); expect(getKey(keySpaceId, `${name}_status`)).to.not.equal(true, `${name} managed to create the document with insufficient rights`); if (hasReadAccess) { let col = db._collection(colName); try { expect(col.document('123').foo).to.not.equal('bar', `${name} managed to create the document with insufficient rights`); } catch (e) {} } } } else { try { tasks.register(task); expect(false).to.equal(true, `${name} managed to register a task with insufficient rights`); } catch (e) { expect(e.errorNum).to.equal(errors.ERROR_FORBIDDEN.code); } } }); it('by aql', () => { expect(rootTestCollection()).to.equal(true, 'Precondition failed, the collection does not exist'); const taskId = 'task_collection_level_create_by_aql' + name; let q = `INSERT {_key: '456', foo: 'bar'} IN ${colName} RETURN NEW`; setKeySpace(keySpaceId, name); const task = { id: taskId, name: taskId, command: `(function (params) { try { const db = require('@arangodb').db; db._query("${q}"); global.KEY_SET('${keySpaceId}', '${name}_status', true); } catch (e) { global.KEY_SET('${keySpaceId}', '${name}_status', false); } finally { global.KEY_SET('${keySpaceId}', '${name}', true); } })(params);` }; if (dbLevel['rw'].has(name)) { if ((dbLevel['rw'].has(name) || dbLevel['ro'].has(name)) && colLevel['rw'].has(name)) { let col = db._collection(colName); tasks.register(task); wait(keySpaceId, name); expect(getKey(keySpaceId, `${name}_status`)).to.equal(true, `${name} the create did not pass through...`); let doc = col.document('456'); expect(doc.foo).to.equal('bar', `${name} the create did not pass through...`); } else { let hasReadAccess = ((dbLevel['rw'].has(name) || dbLevel['ro'].has(name)) && (colLevel['rw'].has(name) || colLevel['ro'].has(name))); tasks.register(task); wait(keySpaceId, name); expect(getKey(keySpaceId, `${name}_status`)).to.not.equal(true, `${name} managed to create the document with insufficient rights`); if (hasReadAccess) { let col = db._collection(colName); try { expect(col.document('456').foo).to.not.equal('bar', `${name} managed to create the document with insufficient rights`); } catch (e) {} } } } else { try { tasks.register(task); expect(false).to.equal(true, `${name} managed to register a task with insufficient rights`); } catch (e) { expect(e.errorNum).to.equal(errors.ERROR_FORBIDDEN.code); } } }); }); }); }); } } }); });