Merge pull request #489 from CartoDB/remove-auth-fallback
Remove auth fallback
This commit is contained in:
commit
f08ad3becd
@ -1,29 +1,38 @@
|
||||
/**
|
||||
* this module allows to auth user using an pregenerated api key
|
||||
*/
|
||||
function ApikeyAuth(req, metadataBackend, username, apikey) {
|
||||
function ApikeyAuth(req, metadataBackend, username, apikeyToken) {
|
||||
this.req = req;
|
||||
this.metadataBackend = metadataBackend;
|
||||
this.username = username;
|
||||
this.apikey = apikey;
|
||||
this.apikeyToken = apikeyToken;
|
||||
}
|
||||
|
||||
module.exports = ApikeyAuth;
|
||||
|
||||
function errorUserNotFoundMessageTemplate (user) {
|
||||
return `Sorry, we can't find CARTO user '${user}'. Please check that you have entered the correct domain.`;
|
||||
function usernameMatches(basicAuthUsername, requestUsername) {
|
||||
return !(basicAuthUsername && (basicAuthUsername !== requestUsername));
|
||||
}
|
||||
|
||||
ApikeyAuth.prototype.verifyCredentials = function (callback) {
|
||||
this.metadataBackend.getApikey(this.username, this.apikey, (err, apikey) => {
|
||||
this.metadataBackend.getApikey(this.username, this.apikeyToken, (err, apikey) => {
|
||||
if (err) {
|
||||
err.http_status = 404;
|
||||
err.message = errorUserNotFoundMessageTemplate(this.username);
|
||||
err.http_status = 500;
|
||||
err.message = 'Unexpected error';
|
||||
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (isApiKeyFound(apikey)) {
|
||||
if (!usernameMatches(apikey.user, this.username)) {
|
||||
const usernameError = new Error('Forbidden');
|
||||
usernameError.type = 'auth';
|
||||
usernameError.subtype = 'api-key-username-mismatch';
|
||||
usernameError.http_status = 403;
|
||||
|
||||
return callback(usernameError);
|
||||
}
|
||||
|
||||
if (!apikey.grantsSql) {
|
||||
const forbiddenError = new Error('forbidden');
|
||||
forbiddenError.http_status = 403;
|
||||
@ -31,33 +40,28 @@ ApikeyAuth.prototype.verifyCredentials = function (callback) {
|
||||
return callback(forbiddenError);
|
||||
}
|
||||
|
||||
return callback(null, verifyRequest(this.apikey, this.apikey));
|
||||
}
|
||||
return callback(null, getAuthorizationLevel(apikey));
|
||||
} else {
|
||||
const apiKeyNotFoundError = new Error('Unauthorized');
|
||||
apiKeyNotFoundError.type = 'auth';
|
||||
apiKeyNotFoundError.subtype = 'api-key-not-found';
|
||||
apiKeyNotFoundError.http_status = 401;
|
||||
|
||||
// Auth API Fallback
|
||||
this.metadataBackend.getAllUserDBParams(this.username, (err, dbParams) => {
|
||||
if (err) {
|
||||
err.http_status = 404;
|
||||
err.message = errorUserNotFoundMessageTemplate(this.username);
|
||||
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, verifyRequest(this.apikey, dbParams.apikey));
|
||||
});
|
||||
return callback(apiKeyNotFoundError);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ApikeyAuth.prototype.hasCredentials = function () {
|
||||
return !!this.apikey;
|
||||
return !!this.apikeyToken;
|
||||
};
|
||||
|
||||
ApikeyAuth.prototype.getCredentials = function () {
|
||||
return this.apikey;
|
||||
return this.apikeyToken;
|
||||
};
|
||||
|
||||
function verifyRequest(apikey, requiredApikey) {
|
||||
return (apikey === requiredApikey && apikey !== 'default_public');
|
||||
function getAuthorizationLevel(apikey) {
|
||||
return apikey.type;
|
||||
}
|
||||
|
||||
function isApiKeyFound(apikey) {
|
||||
|
@ -3,33 +3,33 @@ var ApiKeyAuth = require('./apikey'),
|
||||
|
||||
function AuthApi(req, requestParams) {
|
||||
this.req = req;
|
||||
this.authBacked = getAuthBackend(req, requestParams);
|
||||
this.authBackend = getAuthBackend(req, requestParams);
|
||||
|
||||
this._hasCredentials = null;
|
||||
}
|
||||
|
||||
AuthApi.prototype.getType = function () {
|
||||
if (this.authBacked instanceof ApiKeyAuth) {
|
||||
if (this.authBackend instanceof ApiKeyAuth) {
|
||||
return 'apiKey';
|
||||
} else if (this.authBacked instanceof OAuthAuth) {
|
||||
} else if (this.authBackend instanceof OAuthAuth) {
|
||||
return 'oAuth';
|
||||
}
|
||||
};
|
||||
|
||||
AuthApi.prototype.hasCredentials = function() {
|
||||
if (this._hasCredentials === null) {
|
||||
this._hasCredentials = this.authBacked.hasCredentials();
|
||||
this._hasCredentials = this.authBackend.hasCredentials();
|
||||
}
|
||||
return this._hasCredentials;
|
||||
};
|
||||
|
||||
AuthApi.prototype.getCredentials = function() {
|
||||
return this.authBacked.getCredentials();
|
||||
return this.authBackend.getCredentials();
|
||||
};
|
||||
|
||||
AuthApi.prototype.verifyCredentials = function(callback) {
|
||||
if (this.hasCredentials()) {
|
||||
this.authBacked.verifyCredentials(callback);
|
||||
this.authBackend.verifyCredentials(callback);
|
||||
} else {
|
||||
callback(null, false);
|
||||
}
|
||||
|
@ -142,7 +142,8 @@ var oAuth = (function(){
|
||||
}, false);
|
||||
},
|
||||
function finishValidation(err, hasValidSignature) {
|
||||
return callback(err, hasValidSignature || null);
|
||||
const authorizationLevel = hasValidSignature ? 'master' : null;
|
||||
return callback(err, authorizationLevel);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -51,13 +51,13 @@ JobController.prototype.route = function (app) {
|
||||
|
||||
function composeJobMiddlewares (metadataBackend, userDatabaseService, jobService, statsdClient, userLimitsService) {
|
||||
return function jobMiddlewares (action, jobMiddleware, endpointGroup) {
|
||||
const forceToBeAuthenticated = true;
|
||||
const forceToBeMaster = true;
|
||||
|
||||
return [
|
||||
initializeProfilerMiddleware('job'),
|
||||
userMiddleware(),
|
||||
userMiddleware(metadataBackend),
|
||||
rateLimitsMiddleware(userLimitsService, endpointGroup),
|
||||
authorizationMiddleware(metadataBackend, forceToBeAuthenticated),
|
||||
authorizationMiddleware(metadataBackend, forceToBeMaster),
|
||||
connectionParamsMiddleware(userDatabaseService),
|
||||
jobMiddleware(jobService),
|
||||
setServedByDBHostHeader(),
|
||||
|
@ -33,12 +33,14 @@ function QueryController(metadataBackend, userDatabaseService, tableCache, stats
|
||||
|
||||
QueryController.prototype.route = function (app) {
|
||||
const { base_url } = global.settings;
|
||||
const forceToBeMaster = false;
|
||||
|
||||
const queryMiddlewares = endpointGroup => {
|
||||
return [
|
||||
initializeProfilerMiddleware('query'),
|
||||
userMiddleware(),
|
||||
userMiddleware(this.metadataBackend),
|
||||
rateLimitsMiddleware(this.userLimitsService, endpointGroup),
|
||||
authorizationMiddleware(this.metadataBackend),
|
||||
authorizationMiddleware(this.metadataBackend, forceToBeMaster),
|
||||
connectionParamsMiddleware(this.userDatabaseService),
|
||||
timeoutLimitsMiddleware(this.metadataBackend),
|
||||
this.handleQuery.bind(this),
|
||||
@ -68,7 +70,7 @@ QueryController.prototype.handleQuery = function (req, res, next) {
|
||||
var filename = requestedFilename;
|
||||
var requestedSkipfields = params.skipfields;
|
||||
|
||||
const { user: username, userDbParams: dbopts, authDbParams, userLimits, authenticated } = res.locals;
|
||||
const { user: username, userDbParams: dbopts, authDbParams, userLimits, authorizationLevel } = res.locals;
|
||||
|
||||
var skipfields;
|
||||
var dp = params.dp; // decimal point digits (defaults to 6)
|
||||
@ -143,7 +145,7 @@ QueryController.prototype.handleQuery = function (req, res, next) {
|
||||
|
||||
var pg = new PSQL(authDbParams);
|
||||
|
||||
var skipCache = authenticated;
|
||||
var skipCache = authorizationLevel === 'master';
|
||||
|
||||
self.queryTables.getAffectedTablesFromQuery(pg, sql, skipCache, function(err, result) {
|
||||
if (err) {
|
||||
@ -162,7 +164,7 @@ QueryController.prototype.handleQuery = function (req, res, next) {
|
||||
}
|
||||
|
||||
checkAborted('setHeaders');
|
||||
if(!pgEntitiesAccessValidator.validate(affectedTables, authenticated)) {
|
||||
if(!pgEntitiesAccessValidator.validate(affectedTables, authorizationLevel)) {
|
||||
const syntaxError = new SyntaxError("system tables are forbidden");
|
||||
syntaxError.http_status = 403;
|
||||
throw(syntaxError);
|
||||
|
@ -1,7 +1,7 @@
|
||||
const AuthApi = require('../auth/auth_api');
|
||||
const basicAuth = require('basic-auth');
|
||||
|
||||
module.exports = function authorization (metadataBackend, forceToBeAuthenticated = false) {
|
||||
module.exports = function authorization (metadataBackend, forceToBeMaster = false) {
|
||||
return function authorizationMiddleware (req, res, next) {
|
||||
const { user } = res.locals;
|
||||
const credentials = getCredentialsFromRequest(req);
|
||||
@ -19,7 +19,7 @@ module.exports = function authorization (metadataBackend, forceToBeAuthenticated
|
||||
const params = Object.assign({ metadataBackend }, res.locals, req.query, req.body);
|
||||
const authApi = new AuthApi(req, params);
|
||||
|
||||
authApi.verifyCredentials(function (err, authenticated) {
|
||||
authApi.verifyCredentials(function (err, authorizationLevel) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('authorization');
|
||||
}
|
||||
@ -28,9 +28,9 @@ module.exports = function authorization (metadataBackend, forceToBeAuthenticated
|
||||
return next(err);
|
||||
}
|
||||
|
||||
res.locals.authenticated = authenticated;
|
||||
res.locals.authorizationLevel = authorizationLevel;
|
||||
|
||||
if (forceToBeAuthenticated && !authenticated) {
|
||||
if (forceToBeMaster && authorizationLevel !== 'master') {
|
||||
return next(new Error('permission denied'));
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
module.exports = function connectionParams (userDatabaseService) {
|
||||
return function connectionParamsMiddleware (req, res, next) {
|
||||
const { user, api_key: apikeyToken, authenticated } = res.locals;
|
||||
const { user, api_key: apikeyToken, authorizationLevel } = res.locals;
|
||||
|
||||
userDatabaseService.getConnectionParams(user, apikeyToken, authenticated,
|
||||
userDatabaseService.getConnectionParams(user, apikeyToken, authorizationLevel,
|
||||
function (err, userDbParams, authDbParams) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('getConnectionParams');
|
||||
|
@ -1,6 +1,6 @@
|
||||
module.exports = function timeoutLimits (metadataBackend) {
|
||||
return function timeoutLimitsMiddleware (req, res, next) {
|
||||
const { user, authenticated } = res.locals;
|
||||
const { user, authorizationLevel } = res.locals;
|
||||
|
||||
metadataBackend.getUserTimeoutRenderLimits(user, function (err, timeoutRenderLimit) {
|
||||
if (req.profiler) {
|
||||
@ -12,7 +12,7 @@ module.exports = function timeoutLimits (metadataBackend) {
|
||||
}
|
||||
|
||||
const userLimits = {
|
||||
timeout: authenticated ? timeoutRenderLimit.render : timeoutRenderLimit.renderPublic
|
||||
timeout: (authorizationLevel === 'master') ? timeoutRenderLimit.render : timeoutRenderLimit.renderPublic
|
||||
};
|
||||
|
||||
res.locals.userLimits = userLimits;
|
||||
|
@ -1,10 +1,36 @@
|
||||
const CdbRequest = require('../models/cartodb_request');
|
||||
|
||||
module.exports = function user () {
|
||||
module.exports = function user(metadataBackend) {
|
||||
const cdbRequest = new CdbRequest();
|
||||
|
||||
return function userMiddleware (req, res, next) {
|
||||
res.locals.user = cdbRequest.userByReq(req);
|
||||
next();
|
||||
res.locals.user = getUserNameFromRequest(req, cdbRequest);
|
||||
|
||||
checkUserExists(metadataBackend, res.locals.user, function(err, userExists) {
|
||||
if (err || !userExists) {
|
||||
const error = new Error('Unauthorized');
|
||||
error.type = 'auth';
|
||||
error.subtype = 'user-not-found';
|
||||
error.http_status = 404;
|
||||
error.message = errorUserNotFoundMessageTemplate(res.locals.user);
|
||||
next(error);
|
||||
}
|
||||
|
||||
return next();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
function getUserNameFromRequest(req, cdbRequest) {
|
||||
return cdbRequest.userByReq(req);
|
||||
}
|
||||
|
||||
function checkUserExists(metadataBackend, userName, callback) {
|
||||
metadataBackend.getUserId(userName, function(err) {
|
||||
callback(err, !err);
|
||||
});
|
||||
}
|
||||
|
||||
function errorUserNotFoundMessageTemplate(user) {
|
||||
return `Sorry, we can't find CARTO user '${user}'. Please check that you have entered the correct domain.`;
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ var JobBackend = require('../batch/job_backend');
|
||||
var JobCanceller = require('../batch/job_canceller');
|
||||
var JobService = require('../batch/job_service');
|
||||
|
||||
var UserDatabaseMetadataService = require('../batch/user_database_metadata_service');
|
||||
|
||||
var cors = require('./middlewares/cors');
|
||||
|
||||
var GenericController = require('./controllers/generic_controller');
|
||||
@ -160,8 +158,7 @@ function App(statsClient) {
|
||||
var jobPublisher = new JobPublisher(redisPool);
|
||||
var jobQueue = new JobQueue(metadataBackend, jobPublisher);
|
||||
var jobBackend = new JobBackend(metadataBackend, jobQueue);
|
||||
var userDatabaseMetadataService = new UserDatabaseMetadataService(metadataBackend);
|
||||
var jobCanceller = new JobCanceller(userDatabaseMetadataService);
|
||||
var jobCanceller = new JobCanceller();
|
||||
var jobService = new JobService(jobBackend, jobCanceller);
|
||||
|
||||
var genericController = new GenericController();
|
||||
|
@ -15,7 +15,7 @@ const FORBIDDEN_ENTITIES = {
|
||||
};
|
||||
|
||||
const Validator = {
|
||||
validate(affectedTables, authenticated) {
|
||||
validate(affectedTables, authorizationLevel) {
|
||||
let hardValidationResult = true;
|
||||
let softValidationResult = true;
|
||||
|
||||
@ -24,7 +24,7 @@ const Validator = {
|
||||
hardValidationResult = this.hardValidation(affectedTables.tables);
|
||||
}
|
||||
|
||||
if (!authenticated) {
|
||||
if (authorizationLevel !== 'master') {
|
||||
softValidationResult = this.softValidation(affectedTables.tables);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
const _ = require('underscore');
|
||||
|
||||
function isApiKeyFound(apikey) {
|
||||
return apikey.type !== null &&
|
||||
apikey.user !== null &&
|
||||
@ -15,6 +13,10 @@ function errorUserNotFoundMessageTemplate (user) {
|
||||
return `Sorry, we can't find CARTO user '${user}'. Please check that you have entered the correct domain.`;
|
||||
}
|
||||
|
||||
function isOauthAuthorization({ apikeyToken, authorizationLevel }) {
|
||||
return (authorizationLevel === 'master') && !apikeyToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback is invoked with `dbParams` and `authDbParams`.
|
||||
* `dbParams` depends on AuthApi verification so it might return a public user with just SELECT permission, where
|
||||
@ -25,7 +27,7 @@ function errorUserNotFoundMessageTemplate (user) {
|
||||
* @param {String} cdbUsername
|
||||
* @param {Function} callback (err, dbParams, authDbParams)
|
||||
*/
|
||||
UserDatabaseService.prototype.getConnectionParams = function (username, apikeyToken, authenticated, callback) {
|
||||
UserDatabaseService.prototype.getConnectionParams = function (username, apikeyToken, authorizationLevel, callback) {
|
||||
this.metadataBackend.getAllUserDBParams(username, (err, dbParams) => {
|
||||
if (err) {
|
||||
err.http_status = 404;
|
||||
@ -34,37 +36,14 @@ UserDatabaseService.prototype.getConnectionParams = function (username, apikeyTo
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
const dbopts = {
|
||||
const commonDBConfiguration = {
|
||||
port: global.settings.db_port,
|
||||
pass: global.settings.db_pubuser_pass
|
||||
host: dbParams.dbhost,
|
||||
dbname: dbParams.dbname,
|
||||
};
|
||||
|
||||
dbopts.host = dbParams.dbhost;
|
||||
dbopts.dbname = dbParams.dbname;
|
||||
dbopts.user = (!!dbParams.dbpublicuser) ? dbParams.dbpublicuser : global.settings.db_pubuser;
|
||||
|
||||
const user = _.template(global.settings.db_user, {user_id: dbParams.dbuser});
|
||||
let pass = null;
|
||||
|
||||
if (global.settings.hasOwnProperty('db_user_pass')) {
|
||||
pass = _.template(global.settings.db_user_pass, {
|
||||
user_id: dbParams.dbuser,
|
||||
user_password: dbParams.dbpass
|
||||
});
|
||||
}
|
||||
|
||||
if (authenticated) {
|
||||
dbopts.user = user;
|
||||
dbopts.pass = pass;
|
||||
}
|
||||
|
||||
let authDbOpts = _.defaults({ user: user, pass: pass }, dbopts);
|
||||
|
||||
if (!apikeyToken) {
|
||||
return callback(null, dbopts, authDbOpts);
|
||||
}
|
||||
|
||||
this.metadataBackend.getApikey(username, apikeyToken, (err, apikey) => {
|
||||
this.metadataBackend.getMasterApikey(username, (err, masterApikey) => {
|
||||
|
||||
if (err) {
|
||||
err.http_status = 404;
|
||||
err.message = errorUserNotFoundMessageTemplate(username);
|
||||
@ -72,16 +51,53 @@ UserDatabaseService.prototype.getConnectionParams = function (username, apikeyTo
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!isApiKeyFound(apikey)) {
|
||||
return callback(null, dbopts, authDbOpts);
|
||||
if (!isApiKeyFound(masterApikey)) {
|
||||
const apiKeyNotFoundError = new Error('Unauthorized');
|
||||
apiKeyNotFoundError.type = 'auth';
|
||||
apiKeyNotFoundError.subtype = 'api-key-not-found';
|
||||
apiKeyNotFoundError.http_status = 401;
|
||||
|
||||
return callback(apiKeyNotFoundError);
|
||||
}
|
||||
|
||||
dbopts.user = apikey.databaseRole;
|
||||
dbopts.pass = apikey.databasePassword;
|
||||
const masterDBConfiguration = Object.assign({
|
||||
user: masterApikey.databaseRole,
|
||||
pass: masterApikey.databasePassword
|
||||
},
|
||||
commonDBConfiguration);
|
||||
|
||||
authDbOpts = _.defaults({ user: user, pass: pass }, dbopts);
|
||||
if (isOauthAuthorization({ apikeyToken, authorizationLevel})) {
|
||||
callback(null, masterDBConfiguration, masterDBConfiguration);
|
||||
}
|
||||
|
||||
callback(null, dbopts, authDbOpts);
|
||||
// Default Api key fallback
|
||||
apikeyToken = apikeyToken || 'default_public';
|
||||
|
||||
this.metadataBackend.getApikey(username, apikeyToken, (err, apikey) => {
|
||||
if (err) {
|
||||
err.http_status = 404;
|
||||
err.message = errorUserNotFoundMessageTemplate(username);
|
||||
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!isApiKeyFound(apikey)) {
|
||||
const apiKeyNotFoundError = new Error('Unauthorized');
|
||||
apiKeyNotFoundError.type = 'auth';
|
||||
apiKeyNotFoundError.subtype = 'api-key-not-found';
|
||||
apiKeyNotFoundError.http_status = 401;
|
||||
|
||||
return callback(apiKeyNotFoundError);
|
||||
}
|
||||
|
||||
const DBConfiguration = Object.assign({
|
||||
user: apikey.databaseRole,
|
||||
pass: apikey.databasePassword
|
||||
},
|
||||
commonDBConfiguration);
|
||||
|
||||
callback(null, DBConfiguration, masterDBConfiguration);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -21,7 +21,7 @@ module.exports = function batchFactory (metadataBackend, redisPool, name, statsd
|
||||
var jobQueue = new JobQueue(metadataBackend, jobPublisher);
|
||||
var jobBackend = new JobBackend(metadataBackend, jobQueue);
|
||||
var queryRunner = new QueryRunner(userDatabaseMetadataService);
|
||||
var jobCanceller = new JobCanceller(userDatabaseMetadataService);
|
||||
var jobCanceller = new JobCanceller();
|
||||
var jobService = new JobService(jobBackend, jobCanceller);
|
||||
var jobRunner = new JobRunner(jobService, jobQueue, queryRunner, metadataBackend, statsdClient);
|
||||
var logger = new BatchLogger(loggerPath);
|
||||
|
@ -2,24 +2,26 @@
|
||||
|
||||
var PSQL = require('cartodb-psql');
|
||||
|
||||
function JobCanceller(userDatabaseMetadataService) {
|
||||
this.userDatabaseMetadataService = userDatabaseMetadataService;
|
||||
function JobCanceller() {
|
||||
}
|
||||
|
||||
module.exports = JobCanceller;
|
||||
|
||||
JobCanceller.prototype.cancel = function (job, callback) {
|
||||
this.userDatabaseMetadataService.getUserMetadata(job.data.user, function (err, userDatabaseMetadata) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
doCancel(job.data.job_id, userDatabaseMetadata, callback);
|
||||
});
|
||||
const dbConfiguration = {
|
||||
host: job.data.host,
|
||||
port: job.data.port,
|
||||
dbname: job.data.dbname,
|
||||
user: job.data.dbuser,
|
||||
pass: job.data.pass,
|
||||
};
|
||||
|
||||
doCancel(job.data.job_id, dbConfiguration, callback);
|
||||
};
|
||||
|
||||
function doCancel(job_id, userDatabaseMetadata, callback) {
|
||||
var pg = new PSQL(userDatabaseMetadata);
|
||||
function doCancel(job_id, dbConfiguration, callback) {
|
||||
var pg = new PSQL(dbConfiguration);
|
||||
|
||||
getQueryPID(pg, job_id, function (err, pid) {
|
||||
if (err) {
|
||||
|
@ -18,13 +18,9 @@ QueryRunner.prototype.run = function (job_id, sql, user, timeout, dbparams, call
|
||||
return this._run(dbparams, job_id, sql, timeout, callback);
|
||||
}
|
||||
|
||||
this.userDatabaseMetadataService.getUserMetadata(user, (err, userDBParams) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
const dbConfigurationError = new Error('Batch Job DB misconfiguration');
|
||||
|
||||
this._run(userDBParams, job_id, sql, timeout, callback);
|
||||
});
|
||||
return callback(dbConfigurationError);
|
||||
};
|
||||
|
||||
QueryRunner.prototype._run = function (dbparams, job_id, sql, timeout, callback) {
|
||||
|
@ -1,7 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore');
|
||||
|
||||
function UserDatabaseMetadataService(metadataBackend) {
|
||||
this.metadataBackend = metadataBackend;
|
||||
}
|
||||
@ -23,20 +21,9 @@ UserDatabaseMetadataService.prototype.parseMetadataToDatabase = function (userDa
|
||||
|
||||
var dbopts = {};
|
||||
|
||||
dbopts.pass = dbParams.dbpass || global.settings.db_pubuser_pass;
|
||||
dbopts.port = dbParams.dbport || global.settings.db_batch_port || global.settings.db_port;
|
||||
dbopts.host = dbParams.dbhost;
|
||||
dbopts.dbname = dbParams.dbname;
|
||||
dbopts.user = (!!dbParams.dbpublicuser) ? dbParams.dbpublicuser : global.settings.db_pubuser;
|
||||
|
||||
// batch is secure so it's going to be authenticated by default
|
||||
dbopts.authenticated = true;
|
||||
dbopts.user = _.template(global.settings.db_user, { user_id: dbParams.dbuser });
|
||||
|
||||
dbopts.pass = _.template(global.settings.db_user_pass, {
|
||||
user_id: dbParams.dbuser,
|
||||
user_password: dbParams.dbpass
|
||||
});
|
||||
|
||||
return dbopts;
|
||||
};
|
||||
|
@ -23,7 +23,7 @@
|
||||
"bunyan": "1.8.1",
|
||||
"cartodb-psql": "0.12.0",
|
||||
"cartodb-query-tables": "0.2.0",
|
||||
"cartodb-redis": "1.0.0",
|
||||
"cartodb-redis": "git://github.com/CartoDB/node-cartodb-redis.git#remove-auth-fallback",
|
||||
"debug": "2.2.0",
|
||||
"express": "~4.13.3",
|
||||
"log4js": "cartodb/log4js-node#cdb",
|
||||
|
@ -6,6 +6,16 @@ var assert = require('../support/assert');
|
||||
describe('app.auth', function() {
|
||||
|
||||
var scenarios = [
|
||||
{
|
||||
desc: 'no api key should fallback to default api key',
|
||||
url: "/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4",
|
||||
statusCode: 200
|
||||
},
|
||||
{
|
||||
desc: 'invalid api key should return 401',
|
||||
url: "/api/v1/sql?api_key=THIS_API_KEY_NOT_EXIST&q=SELECT%20*%20FROM%20untitle_table_4",
|
||||
statusCode: 401
|
||||
},
|
||||
{
|
||||
desc: 'valid api key should allow insert in protected tables',
|
||||
url: "/api/v1/sql?api_key=1234&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('app_auth_test1')",
|
||||
@ -18,13 +28,8 @@ describe('app.auth', function() {
|
||||
},
|
||||
{
|
||||
desc: 'invalid api key should NOT allow insert in protected tables',
|
||||
url: "/api/v1/sql?api_key=RAMBO&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('RAMBO')",
|
||||
statusCode: 403
|
||||
},
|
||||
{
|
||||
desc: 'invalid api key (old redis location) should NOT allow insert in protected tables',
|
||||
url: "/api/v1/sql?api_key=1235&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('RAMBO')",
|
||||
statusCode: 403
|
||||
url: "/api/v1/sql?api_key=THIS_API_KEY_NOT_EXIST&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('R')",
|
||||
statusCode: 401
|
||||
},
|
||||
{
|
||||
desc: 'no api key should NOT allow insert in protected tables',
|
||||
|
@ -18,33 +18,18 @@ describe('Auth API', function () {
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: this is obviously a really dangerous sceneario, but in order to not break
|
||||
// some uses cases (i.e: new carto.js examples) and keep backwards compatiblity we will keep it during some time.
|
||||
// It should be fixed as soon as possible
|
||||
it('should get result from query using a wrong API key', function (done) {
|
||||
this.testClient = new TestClient({ apiKey: 'wrong' });
|
||||
it('should fail when using a wrong API key', function (done) {
|
||||
this.testClient = new TestClient({ apiKey: 'THIS_API_KEY_DOES_NOT_EXIST' });
|
||||
|
||||
this.testClient.getResult(publicSQL, (err, result) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(result.length, 6);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: this is obviously a really dangerous sceneario, but in order to not break
|
||||
// some uses cases (i.e: new carto.js examples) and keep backwards compatiblity we will keep it during some time.
|
||||
// It should be fixed as soon as possible
|
||||
it('should fail while fetching data (private dataset) and using a wrong API key', function (done) {
|
||||
this.testClient = new TestClient({ apiKey: 'wrong' });
|
||||
const expectedResponse = {
|
||||
response: {
|
||||
status: 403
|
||||
status: 401
|
||||
}
|
||||
};
|
||||
|
||||
this.testClient.getResult(privateSQL, expectedResponse, (err, result) => {
|
||||
this.testClient.getResult(publicSQL, expectedResponse, (err, result) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(result.error, 'permission denied for relation private_table');
|
||||
assert.equal(result.error, 'Unauthorized');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -106,63 +91,9 @@ describe('Auth API', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Fallback', function () {
|
||||
it('should get result from query using master apikey (fallback) and a granted dataset', function (done) {
|
||||
this.testClient = new TestClient({ apiKey: '4321', host: 'cartofante.cartodb.com' });
|
||||
this.testClient.getResult(scopedSQL, (err, result) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(result.length, 4);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail while getting result from query using metadata and scoped dataset', function (done) {
|
||||
this.testClient = new TestClient({ host: 'cartofante.cartodb.com' });
|
||||
|
||||
const expectedResponse = {
|
||||
response: {
|
||||
status: 403
|
||||
},
|
||||
anonymous: true
|
||||
};
|
||||
|
||||
this.testClient.getResult(privateSQL, expectedResponse, (err, result) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(result.error, 'permission denied for relation private_table');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should insert and delete values on scoped datase using the master apikey', function (done) {
|
||||
this.testClient = new TestClient({ apiKey: 4321, host: 'cartofante.cartodb.com' });
|
||||
|
||||
const insertSql = "INSERT INTO scoped_table_1(name) VALUES('wadus1')";
|
||||
|
||||
this.testClient.getResult(insertSql, (err, rows, body) => {
|
||||
assert.ifError(err);
|
||||
|
||||
assert.ok(body.hasOwnProperty('time'));
|
||||
assert.equal(body.total_rows, 1);
|
||||
assert.equal(rows.length, 0);
|
||||
|
||||
const deleteSql = "DELETE FROM scoped_table_1 WHERE name = 'wadus1'";
|
||||
|
||||
this.testClient.getResult(deleteSql, (err, rows, body) => {
|
||||
assert.ifError(err);
|
||||
|
||||
assert.ok(body.hasOwnProperty('time'));
|
||||
assert.equal(body.total_rows, 1);
|
||||
assert.equal(rows.length, 0);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Batch API', function () {
|
||||
it('should create a job with regular api key and get it done', function (done) {
|
||||
this.testClient = new BatchTestClient({ apiKey: 'regular1' });
|
||||
it('should create a job with master api key and get it done', function (done) {
|
||||
this.testClient = new BatchTestClient({ apiKey: '1234' });
|
||||
|
||||
this.testClient.createJob({ query: scopedSQL }, (err, jobResult) => {
|
||||
if (err) {
|
||||
@ -184,21 +115,42 @@ describe('Auth API', function () {
|
||||
it('should create a job with regular api key and get it failed', function (done) {
|
||||
this.testClient = new BatchTestClient({ apiKey: 'regular1' });
|
||||
|
||||
this.testClient.createJob({ query: privateSQL }, (err, jobResult) => {
|
||||
this.testClient.createJob({ query: privateSQL }, { response: 403 }, (err, response) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
jobResult.getStatus(function (err, job) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
const body = JSON.parse(response.body);
|
||||
assert.equal(body.error, 'permission denied');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
assert.equal(job.status, JobStatus.FAILED);
|
||||
assert.equal(job.failed_reason, 'permission denied for relation private_table');
|
||||
it('should create a job with default public api key and get it failed', function (done) {
|
||||
this.testClient = new BatchTestClient({ apiKey: 'default_public' });
|
||||
|
||||
done();
|
||||
});
|
||||
this.testClient.createJob({ query: publicSQL }, { response: 403 }, (err, response) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
const body = JSON.parse(response.body);
|
||||
assert.equal(body.error, 'permission denied');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a job with fallback default public api key and get it failed', function (done) {
|
||||
this.testClient = new BatchTestClient();
|
||||
|
||||
this.testClient.createJob({ query: publicSQL }, { response: 403, anonymous: true }, (err, response) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
const body = JSON.parse(response.body);
|
||||
assert.equal(body.error, 'permission denied');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@ -267,77 +219,49 @@ describe('Auth API', function () {
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: this is obviously a really dangerous sceneario, but in order to not break
|
||||
// some uses cases (i.e: new carto.js examples) and to keep backwards compatiblity
|
||||
// we will keep it during some time. It should be fixed as soon as possible
|
||||
it('should get result from query using a wrong API key and quering to public dataset', function (done) {
|
||||
this.testClient = new TestClient({ authorization: 'vizzuality:wrong' });
|
||||
it('should fail when querying using a wrong API key', function (done) {
|
||||
this.testClient = new TestClient({ authorization: 'vizzuality:THIS_API_KEY_DOES_NOT_EXIST' });
|
||||
|
||||
this.testClient.getResult(publicSQL, { anonymous: true }, (err, result) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(result.length, 6);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: this is obviously a really dangerous sceneario, but in order to not break
|
||||
// some uses cases (i.e: new carto.js examples) and to keep backwards compatiblity
|
||||
// we will keep it during some time. It should be fixed as soon as possible
|
||||
it('should fail while fetching data (private dataset) and using a wrong API key', function (done) {
|
||||
this.testClient = new TestClient({ authorization: 'vizzuality:wrong' });
|
||||
const expectedResponse = {
|
||||
response: {
|
||||
status: 403
|
||||
status: 401
|
||||
},
|
||||
anonymous: true
|
||||
};
|
||||
|
||||
this.testClient.getResult(privateSQL, expectedResponse, (err, result) => {
|
||||
this.testClient.getResult(publicSQL, expectedResponse, (err, result) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(result.error, 'permission denied for relation private_table');
|
||||
assert.equal(result.error, 'Unauthorized');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Batch API', function () {
|
||||
it('should create a job with regular api key and get it done', function (done) {
|
||||
this.testClient = new BatchTestClient({ authorization: 'vizzuality:regular1' });
|
||||
it('should create a job with regular api key and get it failed', function (done) {
|
||||
this.testClient = new BatchTestClient({ authorization: 'vizzuality:regular1', response: 403 });
|
||||
|
||||
this.testClient.createJob({ query: scopedSQL }, { anonymous: true }, (err, jobResult) => {
|
||||
this.testClient.createJob({ query: scopedSQL }, { anonymous: true }, (err, response) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
jobResult.getStatus(function (err, job) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.equal(job.status, JobStatus.DONE);
|
||||
|
||||
done();
|
||||
});
|
||||
const body = JSON.parse(response.body);
|
||||
assert.equal(body.error, 'permission denied');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a job with regular api key and get it failed', function (done) {
|
||||
this.testClient = new BatchTestClient({ authorization: 'vizzuality:regular1' });
|
||||
it('should create a job with default api key and get it failed', function (done) {
|
||||
this.testClient = new BatchTestClient({ authorization: 'vizzuality:default_public', response: 403 });
|
||||
|
||||
this.testClient.createJob({ query: privateSQL }, { anonymous: true }, (err, jobResult) => {
|
||||
this.testClient.createJob({ query: privateSQL }, { anonymous: true }, (err, response) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
jobResult.getStatus(function (err, job) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.equal(job.status, JobStatus.FAILED);
|
||||
assert.equal(job.failed_reason, 'permission denied for relation private_table');
|
||||
|
||||
done();
|
||||
});
|
||||
const body = JSON.parse(response.body);
|
||||
assert.equal(body.error, 'permission denied');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,6 @@ var JobPublisher = require('../../../batch/pubsub/job-publisher');
|
||||
var JobQueue = require('../../../batch/job_queue');
|
||||
var JobBackend = require('../../../batch/job_backend');
|
||||
var JobService = require('../../../batch/job_service');
|
||||
var UserDatabaseMetadataService = require('../../../batch/user_database_metadata_service');
|
||||
var JobCanceller = require('../../../batch/job_canceller');
|
||||
var metadataBackend = require('cartodb-redis')({ pool: redisUtils.getPool() });
|
||||
|
||||
@ -18,8 +17,7 @@ describe('batch module', function() {
|
||||
var jobPublisher = new JobPublisher(pool);
|
||||
var jobQueue = new JobQueue(metadataBackend, jobPublisher);
|
||||
var jobBackend = new JobBackend(metadataBackend, jobQueue);
|
||||
var userDatabaseMetadataService = new UserDatabaseMetadataService(metadataBackend);
|
||||
var jobCanceller = new JobCanceller(userDatabaseMetadataService);
|
||||
var jobCanceller = new JobCanceller();
|
||||
var jobService = new JobService(jobBackend, jobCanceller);
|
||||
|
||||
before(function (done) {
|
||||
@ -37,7 +35,11 @@ describe('batch module', function() {
|
||||
var data = {
|
||||
user: username,
|
||||
query: sql,
|
||||
host: dbInstance
|
||||
host: dbInstance,
|
||||
dbname: 'cartodb_test_user_1_db',
|
||||
dbuser: 'test_cartodb_user_1',
|
||||
port: 5432,
|
||||
pass: 'test_cartodb_user_1_pass',
|
||||
};
|
||||
|
||||
jobService.create(data, function (err, job) {
|
||||
@ -60,7 +62,6 @@ describe('batch module', function() {
|
||||
if (err) {
|
||||
done(err);
|
||||
}
|
||||
|
||||
assert.equal(job.status, 'running');
|
||||
|
||||
self.batch.drain(function () {
|
||||
|
@ -79,7 +79,7 @@ describe('job module', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('POST /api/v2/sql/job with wrong api key should respond with 403 permission denied', function (done){
|
||||
it('POST /api/v2/sql/job with wrong api key should respond with 401 permission denied', function (done){
|
||||
assert.response(server, {
|
||||
url: '/api/v2/sql/job?api_key=wrong',
|
||||
headers: { 'host': 'vizzuality.cartodb.com', 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
@ -88,10 +88,10 @@ describe('job module', function() {
|
||||
query: "SELECT * FROM untitle_table_4"
|
||||
})
|
||||
}, {
|
||||
status: 403
|
||||
status: 401
|
||||
}, function(err, res) {
|
||||
var error = JSON.parse(res.body);
|
||||
assert.deepEqual(error, { error: [ 'permission denied' ] });
|
||||
assert.deepEqual(error, { error: [ 'Unauthorized' ] });
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -134,16 +134,16 @@ describe('job module', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('GET /api/v2/sql/job/:job_id with wrong api key should respond with 403 permission denied', function (done){
|
||||
it('GET /api/v2/sql/job/:job_id with wrong api key should respond with 401 permission denied', function (done){
|
||||
assert.response(server, {
|
||||
url: '/api/v2/sql/job/' + job.job_id + '?api_key=wrong',
|
||||
headers: { 'host': 'vizzuality.cartodb.com', 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
method: 'GET'
|
||||
}, {
|
||||
status: 403
|
||||
status: 401
|
||||
}, function(err, res) {
|
||||
var error = JSON.parse(res.body);
|
||||
assert.deepEqual(error, { error: [ 'permission denied' ] });
|
||||
assert.deepEqual(error, { error: ['Unauthorized'] });
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -182,16 +182,16 @@ describe('job module', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('DELETE /api/v2/sql/job/:job_id with wrong api key should respond with 403 permission denied', function (done){
|
||||
it('DELETE /api/v2/sql/job/:job_id with wrong api key should respond with 401 permission denied', function (done){
|
||||
assert.response(server, {
|
||||
url: '/api/v2/sql/job/' + job.job_id + '?api_key=wrong',
|
||||
headers: { 'host': 'vizzuality.cartodb.com', 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
method: 'DELETE'
|
||||
}, {
|
||||
status: 403
|
||||
status: 401
|
||||
}, function(err, res) {
|
||||
var error = JSON.parse(res.body);
|
||||
assert.deepEqual(error, { error: [ 'permission denied' ] });
|
||||
assert.deepEqual(error, { error: ['Unauthorized'] });
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -74,7 +74,7 @@ describe('query-tables-api', function() {
|
||||
});
|
||||
|
||||
it('should skip cache to retrieve affected tables', function(done) {
|
||||
var authenticatedRequest = {
|
||||
var masterRequest = {
|
||||
url: '/api/v1/sql?' + qs.stringify({
|
||||
q: 'SELECT * FROM untitle_table_4',
|
||||
api_key: '1234'
|
||||
@ -84,7 +84,7 @@ describe('query-tables-api', function() {
|
||||
},
|
||||
method: 'GET'
|
||||
};
|
||||
assert.response(server, authenticatedRequest, RESPONSE_OK, function(err) {
|
||||
assert.response(server, masterRequest, RESPONSE_OK, function(err) {
|
||||
assert.ok(!err, err);
|
||||
|
||||
getCacheStatus(function(err, cacheStatus) {
|
||||
|
@ -10,7 +10,6 @@ var JobQueue = require('../../../batch/job_queue');
|
||||
|
||||
var JobBackend = require('../../../batch/job_backend');
|
||||
var JobService = require('../../../batch/job_service');
|
||||
var UserDatabaseMetadataService = require('../../../batch/user_database_metadata_service');
|
||||
var JobCanceller = require('../../../batch/job_canceller');
|
||||
var metadataBackend = require('cartodb-redis')({ pool: redisUtils.getPool() });
|
||||
|
||||
@ -19,8 +18,7 @@ describe('job queue', function () {
|
||||
var jobPublisher = new JobPublisher(pool);
|
||||
var jobQueue = new JobQueue(metadataBackend, jobPublisher);
|
||||
var jobBackend = new JobBackend(metadataBackend, jobQueue);
|
||||
var userDatabaseMetadataService = new UserDatabaseMetadataService(metadataBackend);
|
||||
var jobCanceller = new JobCanceller(userDatabaseMetadataService);
|
||||
var jobCanceller = new JobCanceller();
|
||||
var jobService = new JobService(jobBackend, jobCanceller);
|
||||
|
||||
var userA = 'userA';
|
||||
|
@ -11,7 +11,6 @@ var JobQueue = require(BATCH_SOURCE + 'job_queue');
|
||||
var JobBackend = require(BATCH_SOURCE + 'job_backend');
|
||||
var JobPublisher = require(BATCH_SOURCE + 'pubsub/job-publisher');
|
||||
var jobStatus = require(BATCH_SOURCE + 'job_status');
|
||||
var UserDatabaseMetadataService = require(BATCH_SOURCE + 'user_database_metadata_service');
|
||||
var JobCanceller = require(BATCH_SOURCE + 'job_canceller');
|
||||
var PSQL = require('cartodb-psql');
|
||||
|
||||
@ -19,7 +18,6 @@ var metadataBackend = require('cartodb-redis')({ pool: redisUtils.getPool() });
|
||||
var jobPublisher = new JobPublisher(redisUtils.getPool());
|
||||
var jobQueue = new JobQueue(metadataBackend, jobPublisher);
|
||||
var jobBackend = new JobBackend(metadataBackend, jobQueue);
|
||||
var userDatabaseMetadataService = new UserDatabaseMetadataService(metadataBackend);
|
||||
var JobFactory = require(BATCH_SOURCE + 'models/job_factory');
|
||||
|
||||
var USER = 'vizzuality';
|
||||
@ -30,7 +28,6 @@ var HOST = 'localhost';
|
||||
// in order to test query cancelation/draining
|
||||
function runQueryHelper(job, callback) {
|
||||
var job_id = job.job_id;
|
||||
var user = job.user;
|
||||
var sql = job.query;
|
||||
|
||||
job.status = jobStatus.RUNNING;
|
||||
@ -40,22 +37,24 @@ function runQueryHelper(job, callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
userDatabaseMetadataService.getUserMetadata(user, function (err, userDatabaseMetadata) {
|
||||
const dbConfiguration = {
|
||||
host: job.host,
|
||||
port: job.port,
|
||||
dbname: job.dbname,
|
||||
user: job.dbuser,
|
||||
pass: job.pass,
|
||||
};
|
||||
|
||||
const pg = new PSQL(dbConfiguration);
|
||||
|
||||
sql = '/* ' + job_id + ' */ ' + sql;
|
||||
|
||||
pg.eventedQuery(sql, function (err, query) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var pg = new PSQL(userDatabaseMetadata);
|
||||
|
||||
sql = '/* ' + job_id + ' */ ' + sql;
|
||||
|
||||
pg.eventedQuery(sql, function (err, query) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, query);
|
||||
});
|
||||
callback(null, query);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -65,12 +64,16 @@ function createWadusJob(query) {
|
||||
return JobFactory.create(JSON.parse(JSON.stringify({
|
||||
user: USER,
|
||||
query: query,
|
||||
host: HOST
|
||||
host: HOST,
|
||||
dbname: 'cartodb_test_user_1_db',
|
||||
dbuser: 'test_cartodb_user_1',
|
||||
port: 5432,
|
||||
pass: 'test_cartodb_user_1_pass',
|
||||
})));
|
||||
}
|
||||
|
||||
describe('job canceller', function() {
|
||||
var jobCanceller = new JobCanceller(userDatabaseMetadataService);
|
||||
var jobCanceller = new JobCanceller();
|
||||
|
||||
after(function (done) {
|
||||
redisUtils.clean('batch:*', done);
|
||||
|
@ -23,7 +23,7 @@ var jobPublisher = new JobPublisher(redisUtils.getPool());
|
||||
var jobQueue = new JobQueue(metadataBackend, jobPublisher);
|
||||
var jobBackend = new JobBackend(metadataBackend, jobQueue);
|
||||
var userDatabaseMetadataService = new UserDatabaseMetadataService(metadataBackend);
|
||||
var jobCanceller = new JobCanceller(userDatabaseMetadataService);
|
||||
var jobCanceller = new JobCanceller();
|
||||
var jobService = new JobService(jobBackend, jobCanceller);
|
||||
var queryRunner = new QueryRunner(userDatabaseMetadataService);
|
||||
var StatsD = require('node-statsd').StatsD;
|
||||
@ -35,7 +35,11 @@ var HOST = 'localhost';
|
||||
var JOB = {
|
||||
user: USER,
|
||||
query: QUERY,
|
||||
host: HOST
|
||||
host: HOST,
|
||||
dbname: 'cartodb_test_user_1_db',
|
||||
dbuser: 'test_cartodb_user_1',
|
||||
port: 5432,
|
||||
pass: 'test_cartodb_user_1_pass',
|
||||
};
|
||||
|
||||
describe('job runner', function() {
|
||||
|
@ -11,7 +11,6 @@ var JobQueue = require(BATCH_SOURCE + 'job_queue');
|
||||
var JobBackend = require(BATCH_SOURCE + 'job_backend');
|
||||
var JobPublisher = require(BATCH_SOURCE + 'pubsub/job-publisher');
|
||||
var jobStatus = require(BATCH_SOURCE + 'job_status');
|
||||
var UserDatabaseMetadataService = require(BATCH_SOURCE + 'user_database_metadata_service');
|
||||
var JobCanceller = require(BATCH_SOURCE + 'job_canceller');
|
||||
var JobService = require(BATCH_SOURCE + 'job_service');
|
||||
var PSQL = require('cartodb-psql');
|
||||
@ -20,8 +19,7 @@ var metadataBackend = require('cartodb-redis')({ pool: redisUtils.getPool() });
|
||||
var jobPublisher = new JobPublisher(redisUtils.getPool());
|
||||
var jobQueue = new JobQueue(metadataBackend, jobPublisher);
|
||||
var jobBackend = new JobBackend(metadataBackend, jobQueue);
|
||||
var userDatabaseMetadataService = new UserDatabaseMetadataService(metadataBackend);
|
||||
var jobCanceller = new JobCanceller(userDatabaseMetadataService);
|
||||
var jobCanceller = new JobCanceller();
|
||||
|
||||
var USER = 'vizzuality';
|
||||
var QUERY = 'select pg_sleep(0)';
|
||||
@ -29,7 +27,12 @@ var HOST = 'localhost';
|
||||
var JOB = {
|
||||
user: USER,
|
||||
query: QUERY,
|
||||
host: HOST
|
||||
host: HOST,
|
||||
dbname: 'cartodb_test_user_1_db',
|
||||
dbuser: 'test_cartodb_user_1',
|
||||
port: 5432,
|
||||
pass: 'test_cartodb_user_1_pass',
|
||||
|
||||
};
|
||||
|
||||
function createWadusDataJob() {
|
||||
@ -40,7 +43,6 @@ function createWadusDataJob() {
|
||||
// in order to test query cancelation/draining
|
||||
function runQueryHelper(job, callback) {
|
||||
var job_id = job.job_id;
|
||||
var user = job.user;
|
||||
var sql = job.query;
|
||||
|
||||
job.status = jobStatus.RUNNING;
|
||||
@ -50,22 +52,24 @@ function runQueryHelper(job, callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
userDatabaseMetadataService.getUserMetadata(user, function (err, userDatabaseMetadata) {
|
||||
const dbConfiguration = {
|
||||
host: job.host,
|
||||
port: job.port,
|
||||
dbname: job.dbname,
|
||||
user: job.dbuser,
|
||||
pass: job.pass,
|
||||
};
|
||||
|
||||
var pg = new PSQL(dbConfiguration);
|
||||
|
||||
sql = '/* ' + job_id + ' */ ' + sql;
|
||||
|
||||
pg.eventedQuery(sql, function (err, query) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var pg = new PSQL(userDatabaseMetadata);
|
||||
|
||||
sql = '/* ' + job_id + ' */ ' + sql;
|
||||
|
||||
pg.eventedQuery(sql, function (err, query) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, query);
|
||||
});
|
||||
callback(null, query);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ HMSET api_keys:vizzuality:default_public \
|
||||
user "vizzuality" \
|
||||
type "default" \
|
||||
grants_sql "true" \
|
||||
database_role "test_windshaft_publicuser" \
|
||||
database_role "testpublicuser" \
|
||||
database_password "public"
|
||||
EOF
|
||||
|
||||
@ -230,7 +230,7 @@ HMSET api_keys:cartodb250user:default_public \
|
||||
user "cartodb250user" \
|
||||
type "default" \
|
||||
grants_sql "true" \
|
||||
database_role "test_windshaft_publicuser" \
|
||||
database_role "testpublicuser" \
|
||||
database_password "public"
|
||||
EOF
|
||||
|
||||
|
@ -80,7 +80,12 @@ BatchTestClient.prototype.createJob = function(job, override, callback) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null, new JobResult(JSON.parse(res.body), this, override));
|
||||
|
||||
if (res.statusCode < 400) {
|
||||
return callback(null, new JobResult(JSON.parse(res.body), this, override));
|
||||
} else {
|
||||
return callback(null, res);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
};
|
||||
|
@ -99,7 +99,7 @@ it('can return user for verified signature', function(done){
|
||||
|
||||
oAuth.verifyRequest(req, metadataBackend, function(err, data){
|
||||
assert.ok(!err, err);
|
||||
assert.equal(data, 1);
|
||||
assert.equal(data, 'master');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -120,7 +120,7 @@ it('can return user for verified signature (for other allowed domains)', functio
|
||||
oAuth.verifyRequest(req, metadataBackend, function(err, data){
|
||||
oAuth.getAllowedHosts = oAuthGetAllowedHostsFn;
|
||||
assert.ok(!err, err);
|
||||
assert.equal(data, 1);
|
||||
assert.equal(data, 'master');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -97,56 +97,56 @@ describe('pg entities access validator with validatePGEntitiesAccess enabled', f
|
||||
});
|
||||
|
||||
it('validate function: should not be validated', function () {
|
||||
let authenticated = true;
|
||||
let authorizationLevel = 'master';
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesCarto }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesCarto }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesCartodbKO }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesCartodbKO }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesPgcatalog }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesPgcatalog }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesInfo }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesInfo }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesPublicKO }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesPublicKO }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesTopologyKO }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesTopologyKO }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
authenticated = false;
|
||||
authorizationLevel = 'regular';
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesCarto }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesCarto }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesCartodbKO }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesCartodbKO }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesPgcatalog }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesPgcatalog }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesInfo }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesInfo }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesPublicKO }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesPublicKO }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
assert.strictEqual(
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesTopologyKO }, authenticated),
|
||||
pgEntitiesAccessValidator.validate({ tables: fakeAffectedTablesTopologyKO }, authorizationLevel),
|
||||
false
|
||||
);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user