Move authorization to auth-api and extract it from user-database-service
This commit is contained in:
parent
6c92781600
commit
b399abee18
@ -1,15 +1,47 @@
|
||||
/**
|
||||
* this module allows to auth user using an pregenerated api key
|
||||
*/
|
||||
function ApikeyAuth(req, apikey) {
|
||||
function ApikeyAuth(req, metadataBackend, username, apikey) {
|
||||
this.req = req;
|
||||
this.metadataBackend = metadataBackend;
|
||||
this.username = username;
|
||||
this.apikey = apikey;
|
||||
}
|
||||
|
||||
module.exports = ApikeyAuth;
|
||||
|
||||
ApikeyAuth.prototype.verifyCredentials = function (options, callback) {
|
||||
callback(null, verifyRequest(this.apikey, options.apiKey));
|
||||
this.metadataBackend.getApikey(this.username, this.apikey, (err, apikey) => {
|
||||
if (err) {
|
||||
err.http_status = 404;
|
||||
err.message = "Sorry, we can't find CartoDB user '" + this.username + "'. " +
|
||||
"Please check that you have entered the correct domain.";
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (isApiKeyFound(apikey)) {
|
||||
if (!apikey.grantsSql) {
|
||||
const forbiddenError = new Error('forbidden');
|
||||
forbiddenError.http_status = 403;
|
||||
|
||||
return callback(forbiddenError);
|
||||
}
|
||||
|
||||
return callback(null, verifyRequest(this.apikey, this.apikey));
|
||||
}
|
||||
|
||||
// Auth API Fallback
|
||||
this.metadataBackend.getAllUserDBParams(this.username, function (err, dbParams) {
|
||||
if (err) {
|
||||
err.http_status = 404;
|
||||
err.message = "Sorry, we can't find CartoDB user '" + this.username + "'. " +
|
||||
"Please check that you have entered the correct domain.";
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, verifyRequest(this.apikey, dbParams.apikey));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ApikeyAuth.prototype.hasCredentials = function () {
|
||||
@ -23,3 +55,10 @@ ApikeyAuth.prototype.getCredentials = function () {
|
||||
function verifyRequest(apikey, requiredApikey) {
|
||||
return (apikey === requiredApikey && apikey !== 'default_public');
|
||||
}
|
||||
|
||||
function isApiKeyFound(apikey) {
|
||||
return apikey.type !== null &&
|
||||
apikey.user !== null &&
|
||||
apikey.databasePassword !== null &&
|
||||
apikey.databaseRole !== null;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
var ApiKeyAuth = require('./apikey'),
|
||||
OAuthAuth = require('./oauth');
|
||||
|
||||
function AuthApi(req,requestParams) {
|
||||
function AuthApi(req, requestParams) {
|
||||
this.req = req;
|
||||
this.authBacked = getAuthBackend(req, requestParams);
|
||||
|
||||
@ -37,7 +37,7 @@ AuthApi.prototype.verifyCredentials = function(options, callback) {
|
||||
|
||||
function getAuthBackend(req, requestParams) {
|
||||
if (requestParams.api_key) {
|
||||
return new ApiKeyAuth(req, requestParams.api_key);
|
||||
return new ApiKeyAuth(req, requestParams.metadataBackend, requestParams.user, requestParams.api_key);
|
||||
} else {
|
||||
return new OAuthAuth(req);
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ const { initializeProfilerMiddleware, finishProfilerMiddleware } = require('../m
|
||||
const authorizationMiddleware = require('../middlewares/authorization');
|
||||
const errorMiddleware = require('../middlewares/error');
|
||||
|
||||
function JobController(userDatabaseService, jobService, statsdClient) {
|
||||
function JobController(metadataBackend, userDatabaseService, jobService, statsdClient) {
|
||||
this.metadataBackend = metadataBackend;
|
||||
this.userDatabaseService = userDatabaseService;
|
||||
this.jobService = jobService;
|
||||
this.statsdClient = statsdClient;
|
||||
@ -16,6 +17,7 @@ module.exports = JobController;
|
||||
JobController.prototype.route = function (app) {
|
||||
const { base_url } = global.settings;
|
||||
const jobMiddlewares = composeJobMiddlewares(
|
||||
this.metadataBackend,
|
||||
this.userDatabaseService,
|
||||
this.jobService,
|
||||
this.statsdClient
|
||||
@ -27,14 +29,14 @@ JobController.prototype.route = function (app) {
|
||||
app.delete(`${base_url}/sql/job/:job_id`, jobMiddlewares('cancel', cancelJob));
|
||||
};
|
||||
|
||||
function composeJobMiddlewares (userDatabaseService, jobService, statsdClient) {
|
||||
function composeJobMiddlewares (metadataBackend, userDatabaseService, jobService, statsdClient) {
|
||||
return function jobMiddlewares (action, jobMiddleware) {
|
||||
const forceToBeAuthenticated = true;
|
||||
|
||||
return [
|
||||
initializeProfilerMiddleware('job'),
|
||||
userMiddleware(),
|
||||
authorizationMiddleware(userDatabaseService, forceToBeAuthenticated),
|
||||
authorizationMiddleware(metadataBackend, userDatabaseService, forceToBeAuthenticated),
|
||||
jobMiddleware(jobService),
|
||||
setServedByDBHostHeader(),
|
||||
finishProfilerMiddleware(),
|
||||
|
@ -18,7 +18,8 @@ const { initializeProfilerMiddleware } = require('../middlewares/profiler');
|
||||
|
||||
var ONE_YEAR_IN_SECONDS = 31536000; // 1 year time to live by default
|
||||
|
||||
function QueryController(userDatabaseService, tableCache, statsd_client) {
|
||||
function QueryController(metadataBackend, userDatabaseService, tableCache, statsd_client) {
|
||||
this.metadataBackend = metadataBackend;
|
||||
this.statsd_client = statsd_client;
|
||||
this.userDatabaseService = userDatabaseService;
|
||||
this.queryTables = new CachedQueryTables(tableCache);
|
||||
@ -29,7 +30,7 @@ QueryController.prototype.route = function (app) {
|
||||
const queryMiddlewares = [
|
||||
initializeProfilerMiddleware('query'),
|
||||
userMiddleware(),
|
||||
authorizationMiddleware(this.userDatabaseService),
|
||||
authorizationMiddleware(this.metadataBackend ,this.userDatabaseService),
|
||||
this.handleQuery.bind(this),
|
||||
errorMiddleware()
|
||||
];
|
||||
|
@ -1,7 +1,7 @@
|
||||
const AuthApi = require('../auth/auth_api');
|
||||
const basicAuth = require('basic-auth');
|
||||
|
||||
module.exports = function authorization (userDatabaseService, forceToBeAuthenticated = false) {
|
||||
module.exports = function authorization (metadataBackend, userDatabaseService, forceToBeAuthenticated = false) {
|
||||
return function authorizationMiddleware (req, res, next) {
|
||||
const { user } = res.locals;
|
||||
const credentials = getCredentialsFromRequest(req);
|
||||
@ -12,27 +12,38 @@ module.exports = function authorization (userDatabaseService, forceToBeAuthentic
|
||||
|
||||
res.locals.api_key = credentials.apiKeyToken;
|
||||
|
||||
const params = Object.assign({}, res.locals, req.query, req.body);
|
||||
const params = Object.assign({ metadataBackend }, res.locals, req.query, req.body);
|
||||
const authApi = new AuthApi(req, params);
|
||||
|
||||
userDatabaseService.getConnectionParams(authApi, user, function (err, userDbParams, authDbParams, userLimits) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('setDBAuth');
|
||||
}
|
||||
|
||||
authApi.verifyCredentials({}, function (err, authenticated) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (forceToBeAuthenticated && !userDbParams.authenticated) {
|
||||
res.locals.authenticated = authenticated;
|
||||
|
||||
if (forceToBeAuthenticated && !authenticated) {
|
||||
return next(new Error('permission denied'));
|
||||
}
|
||||
|
||||
res.locals.userDbParams = userDbParams;
|
||||
res.locals.authDbParams = authDbParams;
|
||||
res.locals.userLimits = userLimits;
|
||||
const apikeyToken = (authApi.getType() === 'apiKey') ? authApi.getCredentials() : undefined;
|
||||
|
||||
next();
|
||||
userDatabaseService.getConnectionParams(user, apikeyToken, authenticated,
|
||||
function (err, userDbParams, authDbParams, userLimits) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('setDBAuth');
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
res.locals.userDbParams = userDbParams;
|
||||
res.locals.authDbParams = authDbParams;
|
||||
res.locals.userLimits = userLimits;
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
@ -147,10 +147,10 @@ function App(statsClient) {
|
||||
var genericController = new GenericController();
|
||||
genericController.route(app);
|
||||
|
||||
var queryController = new QueryController(userDatabaseService, tableCache, statsClient);
|
||||
var queryController = new QueryController(metadataBackend, userDatabaseService, tableCache, statsClient);
|
||||
queryController.route(app);
|
||||
|
||||
var jobController = new JobController(userDatabaseService, jobService, statsClient);
|
||||
var jobController = new JobController(metadataBackend, userDatabaseService, jobService, statsClient);
|
||||
jobController.route(app);
|
||||
|
||||
var cacheStatusController = new CacheStatusController(tableCache);
|
||||
|
@ -24,7 +24,7 @@ function UserDatabaseService(metadataBackend) {
|
||||
* @param {String} cdbUsername
|
||||
* @param {Function} callback (err, dbParams, authDbParams)
|
||||
*/
|
||||
UserDatabaseService.prototype.getConnectionParams = function (authApi, cdbUsername, callback) {
|
||||
UserDatabaseService.prototype.getConnectionParams = function (cdbUsername, apikeyToken, isAuthenticated, callback) {
|
||||
var self = this;
|
||||
|
||||
var dbopts = {
|
||||
@ -49,35 +49,26 @@ UserDatabaseService.prototype.getConnectionParams = function (authApi, cdbUserna
|
||||
|
||||
const next = this;
|
||||
|
||||
if (authApi.getType() !== 'apiKey') {
|
||||
if (apikeyToken === undefined) {
|
||||
return next(null, dbopts, dbParams);
|
||||
}
|
||||
|
||||
const apikeyToken = authApi.getCredentials();
|
||||
|
||||
self.metadataBackend.getApikey(cdbUsername, apikeyToken, (err, apikey) => {
|
||||
self.getApiKey(cdbUsername, apikeyToken, function (err, apikey) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (!isApiKeyFound(apikey)) {
|
||||
if (!apikey) {
|
||||
return next(null, dbopts, dbParams);
|
||||
}
|
||||
|
||||
if (!apikey.grantsSql) {
|
||||
const forbiddenError = new Error('forbidden');
|
||||
forbiddenError.http_status = 403;
|
||||
|
||||
return next(forbiddenError);
|
||||
}
|
||||
|
||||
dbParams.apikey = apikeyToken;
|
||||
|
||||
next(null, dbopts, dbParams, apikey);
|
||||
});
|
||||
},
|
||||
function authenticate(err, dbopts, dbParams, apikey) {
|
||||
var next = this;
|
||||
function setDBAuth(err, dbopts, dbParams, apikey) {
|
||||
const next = this;
|
||||
|
||||
if (err) {
|
||||
return next(err);
|
||||
@ -87,26 +78,6 @@ UserDatabaseService.prototype.getConnectionParams = function (authApi, cdbUserna
|
||||
dbopts.dbname = dbParams.dbname;
|
||||
dbopts.user = (!!dbParams.dbpublicuser) ? dbParams.dbpublicuser : global.settings.db_pubuser;
|
||||
|
||||
const opts = {
|
||||
metadataBackend: self.metadataBackend,
|
||||
apiKey: dbParams.apikey
|
||||
};
|
||||
|
||||
authApi.verifyCredentials(opts, function (err, isAuthenticated) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
next(null, isAuthenticated, dbopts, dbParams, apikey);
|
||||
});
|
||||
},
|
||||
function setDBAuth(err, isAuthenticated, dbopts, dbParams, apikey) {
|
||||
const next = this;
|
||||
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var user = _.template(global.settings.db_user, {user_id: dbParams.dbuser});
|
||||
var pass = null;
|
||||
|
||||
@ -139,15 +110,11 @@ UserDatabaseService.prototype.getConnectionParams = function (authApi, cdbUserna
|
||||
return next(err);
|
||||
}
|
||||
|
||||
self.metadataBackend.getUserTimeoutRenderLimits(cdbUsername, function (err, timeoutRenderLimit) {
|
||||
self.getUserLimits(cdbUsername, isAuthenticated, function (err, userLimits) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var userLimits = {
|
||||
timeout: isAuthenticated ? timeoutRenderLimit.render : timeoutRenderLimit.renderPublic
|
||||
};
|
||||
|
||||
next(null, dbopts, authDbOpts, userLimits);
|
||||
});
|
||||
},
|
||||
@ -161,4 +128,32 @@ UserDatabaseService.prototype.getConnectionParams = function (authApi, cdbUserna
|
||||
);
|
||||
};
|
||||
|
||||
UserDatabaseService.prototype.getApiKey = function (cdbUsername, apikeyToken, callback) {
|
||||
this.metadataBackend.getApikey(cdbUsername, apikeyToken, (err, apikey) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!isApiKeyFound(apikey)) {
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
callback(null, apikey);
|
||||
});
|
||||
};
|
||||
|
||||
UserDatabaseService.prototype.getUserLimits = function (cdbUsername, isAuthenticated, callback) {
|
||||
this.metadataBackend.getUserTimeoutRenderLimits(cdbUsername, function (err, timeoutRenderLimit) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var userLimits = {
|
||||
timeout: isAuthenticated ? timeoutRenderLimit.render : timeoutRenderLimit.renderPublic
|
||||
};
|
||||
|
||||
callback(null, userLimits);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = UserDatabaseService;
|
||||
|
Loading…
Reference in New Issue
Block a user