From f4ea39b602a4074a2bacd414671d5376430f6303 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Wed, 3 Feb 2016 10:02:39 +0100 Subject: [PATCH] Initial commit. --- packages/xo-acl-resolver/.babelrc | 8 ++ packages/xo-acl-resolver/.editorconfig | 65 ++++++++++++ packages/xo-acl-resolver/.gitignore | 9 ++ packages/xo-acl-resolver/.mocha.js | 5 + packages/xo-acl-resolver/.mocha.opts | 1 + packages/xo-acl-resolver/.npmignore | 10 ++ packages/xo-acl-resolver/.travis.yml | 9 ++ packages/xo-acl-resolver/README.md | 52 +++++++++ packages/xo-acl-resolver/package.json | 56 ++++++++++ packages/xo-acl-resolver/src/index.js | 118 +++++++++++++++++++++ packages/xo-acl-resolver/src/index.spec.js | 17 +++ 11 files changed, 350 insertions(+) create mode 100644 packages/xo-acl-resolver/.babelrc create mode 100644 packages/xo-acl-resolver/.editorconfig create mode 100644 packages/xo-acl-resolver/.gitignore create mode 100644 packages/xo-acl-resolver/.mocha.js create mode 100644 packages/xo-acl-resolver/.mocha.opts create mode 100644 packages/xo-acl-resolver/.npmignore create mode 100644 packages/xo-acl-resolver/.travis.yml create mode 100644 packages/xo-acl-resolver/README.md create mode 100644 packages/xo-acl-resolver/package.json create mode 100644 packages/xo-acl-resolver/src/index.js create mode 100644 packages/xo-acl-resolver/src/index.spec.js diff --git a/packages/xo-acl-resolver/.babelrc b/packages/xo-acl-resolver/.babelrc new file mode 100644 index 000000000..0a89ba36d --- /dev/null +++ b/packages/xo-acl-resolver/.babelrc @@ -0,0 +1,8 @@ +{ + "comments": false, + "compact": true, + "presets": [ + "stage-0", + "es2015" + ] +} diff --git a/packages/xo-acl-resolver/.editorconfig b/packages/xo-acl-resolver/.editorconfig new file mode 100644 index 000000000..da21ef4c5 --- /dev/null +++ b/packages/xo-acl-resolver/.editorconfig @@ -0,0 +1,65 @@ +# http://EditorConfig.org +# +# Julien Fontanet's configuration +# https://gist.github.com/julien-f/8096213 + +# Top-most EditorConfig file. +root = true + +# Common config. +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespaces = true + +# CoffeeScript +# +# https://github.com/polarmobile/coffeescript-style-guide/blob/master/README.md +[*.{,lit}coffee] +indent_size = 2 +indent_style = space + +# Markdown +[*.{md,mdwn,mdown,markdown}] +indent_size = 4 +indent_style = space + +# Package.json +# +# This indentation style is the one used by npm. +[/package.json] +indent_size = 2 +indent_style = space + +# Jade +[*.jade] +indent_size = 2 +indent_style = space + +# JavaScript +# +# Two spaces seems to be the standard most common style, at least in +# Node.js (http://nodeguide.com/style.html#tabs-vs-spaces). +[*.js] +indent_size = 2 +indent_style = space + +# Less +[*.less] +indent_size = 2 +indent_style = space + +# Sass +# +# Style used for http://libsass.com +[*.s[ac]ss] +indent_size = 2 +indent_style = space + +# YAML +# +# Only spaces are allowed. +[*.yaml] +indent_size = 2 +indent_style = space diff --git a/packages/xo-acl-resolver/.gitignore b/packages/xo-acl-resolver/.gitignore new file mode 100644 index 000000000..6959be1cf --- /dev/null +++ b/packages/xo-acl-resolver/.gitignore @@ -0,0 +1,9 @@ +/.nyc_output/ +/bower_components/ +/dist/ + +npm-debug.log +npm-debug.log.* + +!node_modules/* +node_modules/*/ diff --git a/packages/xo-acl-resolver/.mocha.js b/packages/xo-acl-resolver/.mocha.js new file mode 100644 index 000000000..e6d84e403 --- /dev/null +++ b/packages/xo-acl-resolver/.mocha.js @@ -0,0 +1,5 @@ +Error.stackTraceLimit = 100 + +try { require('trace') } catch (_) {} +try { require('clarify') } catch (_) {} +try { require('source-map-support/register') } catch (_) {} diff --git a/packages/xo-acl-resolver/.mocha.opts b/packages/xo-acl-resolver/.mocha.opts new file mode 100644 index 000000000..6cfd94898 --- /dev/null +++ b/packages/xo-acl-resolver/.mocha.opts @@ -0,0 +1 @@ +--require ./.mocha.js diff --git a/packages/xo-acl-resolver/.npmignore b/packages/xo-acl-resolver/.npmignore new file mode 100644 index 000000000..c31ee82cb --- /dev/null +++ b/packages/xo-acl-resolver/.npmignore @@ -0,0 +1,10 @@ +/examples/ +example.js +example.js.map +*.example.js +*.example.js.map + +/test/ +/tests/ +*.spec.js +*.spec.js.map diff --git a/packages/xo-acl-resolver/.travis.yml b/packages/xo-acl-resolver/.travis.yml new file mode 100644 index 000000000..a9b136ea6 --- /dev/null +++ b/packages/xo-acl-resolver/.travis.yml @@ -0,0 +1,9 @@ +language: node_js +node_js: + - 'stable' + - '4' + - '0.12' + +# Use containers. +# http://docs.travis-ci.com/user/workers/container-based-infrastructure/ +sudo: false diff --git a/packages/xo-acl-resolver/README.md b/packages/xo-acl-resolver/README.md new file mode 100644 index 000000000..6904d5bae --- /dev/null +++ b/packages/xo-acl-resolver/README.md @@ -0,0 +1,52 @@ +# xo-acl-resolver [![Build Status](https://travis-ci.org/vatesfr/xo-acl-resolver.png?branch=master)](https://travis-ci.org/vatesfr/xo-acl-resolver) + +> [Xen-Orchestra](http://xen-orchestra.com/) internal: do ACLs resolution. + +## Install + +Installation of the [npm package](https://npmjs.org/package/xo-acl-resolver): + +``` +> npm install --save xo-acl-resolver +``` + +## Usage + +**TODO** + +## Development + +### Installing dependencies + +``` +> npm install +``` + +### Compilation + +The sources files are watched and automatically recompiled on changes. + +``` +> npm run dev +``` + +### Tests + +``` +> npm run test-dev +``` + +## Contributions + +Contributions are *very* welcomed, either on the documentation or on +the code. + +You may: + +- report any [issue](https://github.com/vatesfr/xo-acl-resolver/issues) + you've encountered; +- fork and create a pull request. + +## License + +ISC © [Vates SAS](https://vates.fr) diff --git a/packages/xo-acl-resolver/package.json b/packages/xo-acl-resolver/package.json new file mode 100644 index 000000000..500ce6922 --- /dev/null +++ b/packages/xo-acl-resolver/package.json @@ -0,0 +1,56 @@ +{ + "name": "xo-acl-resolver", + "version": "0.0.0", + "license": "ISC", + "description": "Xen-Orchestra internal: do ACLs resolution", + "keywords": [], + "homepage": "https://github.com/vatesfr/xo-acl-resolver", + "bugs": "https://github.com/vatesfr/xo-acl-resolver/issues", + "repository": { + "type": "git", + "url": "https://github.com/vatesfr/xo-acl-resolver" + }, + "author": { + "name": "Julien Fontanet", + "email": "julien.fontanet@vates.fr" + }, + "preferGlobal": false, + "main": "dist/", + "bin": {}, + "files": [ + "dist/" + ], + "engines": { + "node": ">=0.12" + }, + "devDependencies": { + "babel-cli": "^6.4.5", + "babel-eslint": "^4.1.8", + "babel-preset-es2015": "^6.3.13", + "babel-preset-stage-0": "^6.3.13", + "clarify": "^1.0.5", + "dependency-check": "^2.5.1", + "mocha": "^2.4.5", + "must": "^0.13.1", + "nyc": "^5.5.0", + "source-map-support": "^0.4.0", + "standard": "^5.4.1", + "trace": "^2.0.2" + }, + "scripts": { + "build": "babel --source-maps --out-dir=dist/ src/", + "depcheck": "dependency-check ./package.json", + "dev": "babel --watch --source-maps --out-dir=dist/ src/", + "dev-test": "mocha --opts .mocha.opts --watch --reporter=min \"dist/**/*.spec.js\"", + "lint": "standard", + "posttest": "npm run lint && npm run depcheck", + "prepublish": "npm run build", + "test": "nyc mocha --opts .mocha.opts \"dist/**/*.spec.js\"" + }, + "standard": { + "ignore": [ + "dist/**" + ], + "parser": "babel-eslint" + } +} diff --git a/packages/xo-acl-resolver/src/index.js b/packages/xo-acl-resolver/src/index.js new file mode 100644 index 000000000..e818d2566 --- /dev/null +++ b/packages/xo-acl-resolver/src/index.js @@ -0,0 +1,118 @@ +// These global variables are not a problem because the algorithm is +// synchronous. +let permissionsByObject +let getObject + +// ------------------------------------------------------------------- + +const authorized = () => true // eslint-disable-line no-unused-vars +const forbiddden = () => false // eslint-disable-line no-unused-vars + +const and = (...checkers) => (object, permission) => { // eslint-disable-line no-unused-vars + for (const checker of checkers) { + if (!checker(object, permission)) { + return false + } + } + return true +} + +const or = (...checkers) => (object, permission) => { // eslint-disable-line no-unused-vars + for (const checker of checkers) { + if (checker(object, permission)) { + return true + } + } + return false +} + +// ------------------------------------------------------------------- + +const checkMember = memberName => (object, permission) => { + const member = object[memberName] + return checkAuthorization(member, permission) +} + +const checkSelf = ({ id }, permission) => { + const permissionsForObject = permissionsByObject[id] + + return ( + permissionsForObject && + permissionsForObject[permission] + ) +} + +// =================================================================== + +const checkAuthorizationByTypes = { + host: or(checkSelf, checkMember('$pool')), + + message: checkMember('$object'), + + network: or(checkSelf, checkMember('$pool')), + + SR: or(checkSelf, checkMember('$pool')), + + task: checkMember('$host'), + + VBD: checkMember('VDI'), + + // Access to a VDI is granted if the user has access to the + // containing SR or to a linked VM. + VDI (vdi, permission) { + // Check authorization for the containing SR. + if (checkAuthorization(vdi.$SR, permission)) { + return true + } + + // Check authorization for each of the connected VMs. + for (const { VM: vm } of vdi.$VBDs) { + if (checkAuthorization(vm, permission)) { + return true + } + } + + return false + }, + + VIF: or(checkMember('$network'), checkMember('$VM')), + + VM: or(checkSelf, checkMember('$container')), + + 'VM-snapshot': checkMember('$snapshot_of'), + + 'VM-template': authorized +} + +// Hoisting is important for this function. +function checkAuthorization (objectId, permission) { + const object = getObject(objectId) + const checker = checkAuthorizationByTypes[object.type] || checkSelf + + return checker(object, permission) +} + +// ------------------------------------------------------------------- + +export default ( + permissionsByObject_, + getObject_, + permissions +) => { + // Assign global variables. + permissionsByObject = permissionsByObject_ + getObject = getObject_ + + try { + for (const [objectId, permission] of permissions) { + if (!checkAuthorization(objectId, permission)) { + return false + } + } + + return true + } finally { + // Free the global variables. + permissionsByObject = getObject = null + } +} diff --git a/packages/xo-acl-resolver/src/index.spec.js b/packages/xo-acl-resolver/src/index.spec.js new file mode 100644 index 000000000..2319bd7d5 --- /dev/null +++ b/packages/xo-acl-resolver/src/index.spec.js @@ -0,0 +1,17 @@ +/* eslint-env mocha */ + +import expect from 'must' + +// =================================================================== + +import myLib from './' + +// =================================================================== + +describe.skip('myLib', () => { + it('does something', () => { + // TODO: some real tests. + + expect(myLib).to.exists() + }) +})