Make accessRestriction a JSON format to prepare for group access control

This commit is contained in:
Johannes Zellner
2015-10-16 15:11:54 +02:00
parent f8c2ebe61a
commit 373db25077
5 changed files with 46 additions and 38 deletions
+13 -4
View File
@@ -59,7 +59,7 @@ var assert = require('assert'),
var APPS_FIELDS_PREFIXED = [ 'apps.id', 'apps.appStoreId', 'apps.installationState', 'apps.installationProgress', 'apps.runState',
'apps.health', 'apps.containerId', 'apps.manifestJson', 'apps.httpPort', 'apps.location', 'apps.dnsRecordId',
'apps.accessRestriction', 'apps.lastBackupId', 'apps.lastBackupConfigJson', 'apps.oldConfigJson', 'apps.oauthProxy' ].join(',');
'apps.accessRestrictionJson', 'apps.lastBackupId', 'apps.lastBackupConfigJson', 'apps.oldConfigJson', 'apps.oauthProxy' ].join(',');
var PORT_BINDINGS_FIELDS = [ 'hostPort', 'environmentVariable', 'appId' ].join(',');
@@ -93,6 +93,11 @@ function postProcess(result) {
}
result.oauthProxy = !!result.oauthProxy;
assert(result.accessRestrictionJson === null || typeof result.accessRestrictionJson === 'string');
result.accessRestriction = safe.JSON.parse(result.accessRestrictionJson);
if (result.accessRestriction && !result.accessRestriction.users) result.accessRestriction.users = [];
delete result.accessRestrictionJson;
}
function get(id, callback) {
@@ -181,18 +186,19 @@ function add(id, appStoreId, manifest, location, portBindings, accessRestriction
assert.strictEqual(typeof manifest.version, 'string');
assert.strictEqual(typeof location, 'string');
assert.strictEqual(typeof portBindings, 'object');
assert.strictEqual(typeof accessRestriction, 'string');
assert.strictEqual(typeof accessRestriction, 'object');
assert.strictEqual(typeof oauthProxy, 'boolean');
assert.strictEqual(typeof callback, 'function');
portBindings = portBindings || { };
var manifestJson = JSON.stringify(manifest);
var accessRestrictionJson = JSON.stringify(accessRestriction);
var queries = [ ];
queries.push({
query: 'INSERT INTO apps (id, appStoreId, manifestJson, installationState, location, accessRestriction, oauthProxy) VALUES (?, ?, ?, ?, ?, ?, ?)',
args: [ id, appStoreId, manifestJson, exports.ISTATE_PENDING_INSTALL, location, accessRestriction, oauthProxy ]
query: 'INSERT INTO apps (id, appStoreId, manifestJson, installationState, location, accessRestrictionJson, oauthProxy) VALUES (?, ?, ?, ?, ?, ?, ?)',
args: [ id, appStoreId, manifestJson, exports.ISTATE_PENDING_INSTALL, location, accessRestrictionJson, oauthProxy ]
});
Object.keys(portBindings).forEach(function (env) {
@@ -301,6 +307,9 @@ function updateWithConstraints(id, app, constraints, callback) {
} else if (p === 'oldConfig') {
fields.push('oldConfigJson = ?');
values.push(JSON.stringify(app[p]));
} else if (p === 'accessRestriction') {
fields.push('accessRestrictionJson = ?');
values.push(JSON.stringify(app[p]));
} else if (p !== 'portBindings') {
fields.push(p + ' = ?');
values.push(app[p]);
+9 -26
View File
@@ -184,16 +184,12 @@ function validatePortBindings(portBindings, tcpPorts) {
}
function validateAccessRestriction(accessRestriction) {
assert.strictEqual(typeof accessRestriction, 'string');
assert.strictEqual(typeof accessRestriction, 'object');
function validator(entry) {
if (entry === '') return true;
if (entry.indexOf('user-') === 0 && entry.length > 'user-'.length) return true;
return false;
}
if (accessRestriction === null) return null;
var entries = accessRestriction.split(',').map(function (e) { return e.trim(); });
if (!entries.every(validator)) return new Error('Invalid accessRestriction');
if (!accessRestriction.users) return new Error('Users property required');
if (!accessRestriction.users.every(function (e) { return typeof e === 'string'; })) return new Error('All users have to be strings');
return null;
}
@@ -229,14 +225,8 @@ function hasAccessTo(app, user) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof user, 'object');
function validator(entry) {
if (entry.indexOf('user-') === 0 && entry.slice('user-'.length) === user.id) return true;
return false;
}
if (app.accessRestriction === '') return true;
return app.accessRestriction.split(',').some(validator);
if (app.accessRestriction === null) return true;
return app.accessRestriction.users.some(function (e) { return e === user.id; });
}
function get(appId, callback) {
@@ -308,7 +298,7 @@ function install(appId, appStoreId, manifest, location, portBindings, accessRest
assert(manifest && typeof manifest === 'object');
assert.strictEqual(typeof location, 'string');
assert.strictEqual(typeof portBindings, 'object');
assert.strictEqual(typeof accessRestriction, 'string');
assert.strictEqual(typeof accessRestriction, 'object');
assert.strictEqual(typeof oauthProxy, 'boolean');
assert(!icon || typeof icon === 'string');
assert.strictEqual(typeof callback, 'function');
@@ -356,7 +346,7 @@ function configure(appId, location, portBindings, accessRestriction, oauthProxy,
assert.strictEqual(typeof appId, 'string');
assert.strictEqual(typeof location, 'string');
assert.strictEqual(typeof portBindings, 'object');
assert.strictEqual(typeof accessRestriction, 'string');
assert.strictEqual(typeof accessRestriction, 'object');
assert.strictEqual(typeof oauthProxy, 'boolean');
assert.strictEqual(typeof callback, 'function');
@@ -401,12 +391,11 @@ function configure(appId, location, portBindings, accessRestriction, oauthProxy,
});
}
function update(appId, force, manifest, portBindings, accessRestriction, icon, callback) {
function update(appId, force, manifest, portBindings, icon, callback) {
assert.strictEqual(typeof appId, 'string');
assert.strictEqual(typeof force, 'boolean');
assert(manifest && typeof manifest === 'object');
assert(!portBindings || typeof portBindings === 'object');
assert(accessRestriction === null || typeof accessRestriction === 'string');
assert(!icon || typeof icon === 'string');
assert.strictEqual(typeof callback, 'function');
@@ -421,11 +410,6 @@ function update(appId, force, manifest, portBindings, accessRestriction, icon, c
error = validatePortBindings(portBindings, manifest.tcpPorts);
if (error) return callback(new AppsError(AppsError.BAD_FIELD, error.message));
if (accessRestriction !== null) {
error = validateAccessRestriction(accessRestriction);
if (error) return callback(new AppsError(AppsError.BAD_FIELD, error.message));
}
if (icon) {
if (!validator.isBase64(icon)) return callback(new AppsError(AppsError.BAD_FIELD, 'icon is not base64'));
@@ -441,7 +425,6 @@ function update(appId, force, manifest, portBindings, accessRestriction, icon, c
var values = {
manifest: manifest,
portBindings: portBindings,
accessRestriction: accessRestriction === null ? app.accessRestriction : accessRestriction,
oldConfig: {
manifest: app.manifest,
portBindings: app.portBindings,
+6 -7
View File
@@ -114,14 +114,14 @@ function installApp(req, res, next) {
if (typeof data.appStoreId !== 'string') return next(new HttpError(400, 'appStoreId is required'));
if (typeof data.location !== 'string') return next(new HttpError(400, 'location is required'));
if (('portBindings' in data) && typeof data.portBindings !== 'object') return next(new HttpError(400, 'portBindings must be an object'));
if (typeof data.accessRestriction !== 'string') return next(new HttpError(400, 'accessRestriction is required'));
if (typeof data.accessRestriction !== 'object') return next(new HttpError(400, 'accessRestriction is required'));
if (typeof data.oauthProxy !== 'boolean') return next(new HttpError(400, 'oauthProxy must be a boolean'));
if ('icon' in data && typeof data.icon !== 'string') return next(new HttpError(400, 'icon is not a string'));
// allow tests to provide an appId for testing
var appId = (process.env.BOX_ENV === 'test' && typeof data.appId === 'string') ? data.appId : uuid.v4();
debug('Installing app id:%s storeid:%s loc:%s port:%j accessRestriction:%s oauthproxy:%s manifest:%j', appId, data.appStoreId, data.location, data.portBindings, data.accessRestriction, data.oauthProxy, data.manifest);
debug('Installing app id:%s storeid:%s loc:%s port:%j accessRestriction:%j oauthproxy:%s manifest:%j', appId, data.appStoreId, data.location, data.portBindings, data.accessRestriction, data.oauthProxy, data.manifest);
apps.install(appId, data.appStoreId, data.manifest, data.location, data.portBindings || null, data.accessRestriction, data.oauthProxy, data.icon || null, function (error) {
if (error && error.reason === AppsError.ALREADY_EXISTS) return next(new HttpError(409, error.message));
@@ -151,10 +151,10 @@ function configureApp(req, res, next) {
if (!data) return next(new HttpError(400, 'Cannot parse data field'));
if (typeof data.location !== 'string') return next(new HttpError(400, 'location is required'));
if (('portBindings' in data) && typeof data.portBindings !== 'object') return next(new HttpError(400, 'portBindings must be an object'));
if (typeof data.accessRestriction !== 'string') return next(new HttpError(400, 'accessRestriction is required'));
if (typeof data.accessRestriction !== 'object') return next(new HttpError(400, 'accessRestriction is required'));
if (typeof data.oauthProxy !== 'boolean') return next(new HttpError(400, 'oauthProxy must be a boolean'));
debug('Configuring app id:%s location:%s bindings:%j accessRestriction:%s oauthProxy:%s', req.params.id, data.location, data.portBindings, data.accessRestriction, data.oauthProxy);
debug('Configuring app id:%s location:%s bindings:%j accessRestriction:%j oauthProxy:%s', req.params.id, data.location, data.portBindings, data.accessRestriction, data.oauthProxy);
apps.configure(req.params.id, data.location, data.portBindings || null, data.accessRestriction, data.oauthProxy, function (error) {
if (error && error.reason === AppsError.ALREADY_EXISTS) return next(new HttpError(409, error.message));
@@ -253,13 +253,12 @@ function updateApp(req, res, next) {
if (!data) return next(new HttpError(400, 'Cannot parse data field'));
if (!data.manifest || typeof data.manifest !== 'object') return next(new HttpError(400, 'manifest is required'));
if (('portBindings' in data) && typeof data.portBindings !== 'object') return next(new HttpError(400, 'portBindings must be an object'));
if (data.accessRestriction !== null && typeof data.accessRestriction !== 'string') return next(new HttpError(400, 'accessRestriction is required'));
if ('icon' in data && typeof data.icon !== 'string') return next(new HttpError(400, 'icon is not a string'));
if ('force' in data && typeof data.force !== 'boolean') return next(new HttpError(400, 'force must be a boolean'));
debug('Update app id:%s to manifest:%j with portBindings:%j accessRestriction:%s', req.params.id, data.manifest, data.portBindings, data.accessRestriction);
debug('Update app id:%s to manifest:%j with portBindings:%j', req.params.id, data.manifest, data.portBindings);
apps.update(req.params.id, data.force || false, data.manifest, data.portBindings, data.accessRestriction, data.icon, function (error) {
apps.update(req.params.id, data.force || false, data.manifest, data.portBindings, data.icon, function (error) {
if (error && error.reason === AppsError.NOT_FOUND) return next(new HttpError(404, 'No such app'));
if (error && error.reason === AppsError.BAD_FIELD) return next(new HttpError(400, error.message));
if (error && error.reason === AppsError.BAD_STATE) return next(new HttpError(409, error.message));