2015-07-13 21:05:03 +08:00
|
|
|
var assert = require('assert');
|
|
|
|
var step = require('step');
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {PgConnection} pgConnection
|
|
|
|
* @param metadataBackend
|
|
|
|
* @param {MapStore} mapStore
|
|
|
|
* @param {TemplateMaps} templateMaps
|
|
|
|
* @constructor
|
|
|
|
* @type {AuthApi}
|
|
|
|
*/
|
|
|
|
function AuthApi(pgConnection, metadataBackend, mapStore, templateMaps) {
|
|
|
|
this.pgConnection = pgConnection;
|
|
|
|
this.metadataBackend = metadataBackend;
|
|
|
|
this.mapStore = mapStore;
|
|
|
|
this.templateMaps = templateMaps;
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = AuthApi;
|
|
|
|
|
2017-10-04 18:50:27 +08:00
|
|
|
// Check if the user is authorized by a signer
|
2015-07-13 21:05:03 +08:00
|
|
|
//
|
2017-10-04 18:50:27 +08:00
|
|
|
// @param res express response object
|
2015-07-13 21:05:03 +08:00
|
|
|
// @param callback function(err, signed_by) signed_by will be
|
|
|
|
// null if the request is not signed by anyone
|
|
|
|
// or will be a string cartodb username otherwise.
|
|
|
|
//
|
2017-10-05 17:28:41 +08:00
|
|
|
AuthApi.prototype.authorizedBySigner = function(res, callback) {
|
|
|
|
if ( ! res.locals.token || ! res.locals.signer ) {
|
2015-07-13 21:05:03 +08:00
|
|
|
return callback(null, false); // no signer requested
|
|
|
|
}
|
|
|
|
|
|
|
|
var self = this;
|
|
|
|
|
2017-10-05 17:28:41 +08:00
|
|
|
var layergroup_id = res.locals.token;
|
|
|
|
var auth_token = res.locals.auth_token;
|
2015-07-13 21:05:03 +08:00
|
|
|
|
|
|
|
this.mapStore.load(layergroup_id, function(err, mapConfig) {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
var authorized = self.templateMaps.isAuthorized(mapConfig.obj().template, auth_token);
|
|
|
|
|
|
|
|
return callback(null, authorized);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2018-02-08 01:20:56 +08:00
|
|
|
function isValidApiKey(apikey) {
|
|
|
|
return apikey.type !== null &&
|
|
|
|
apikey.user !== null &&
|
|
|
|
apikey.databasePassword !== null &&
|
|
|
|
apikey.databaseRole !== null;
|
|
|
|
}
|
|
|
|
|
2015-07-13 21:05:03 +08:00
|
|
|
// Check if a request is authorized by api_key
|
|
|
|
//
|
|
|
|
// @param user
|
|
|
|
// @param req express request object
|
|
|
|
// @param callback function(err, authorized)
|
|
|
|
// NOTE: authorized is expected to be 0 or 1 (integer)
|
|
|
|
//
|
|
|
|
AuthApi.prototype.authorizedByAPIKey = function(user, req, callback) {
|
|
|
|
var givenKey = req.query.api_key || req.query.map_key;
|
|
|
|
if ( ! givenKey && req.body ) {
|
|
|
|
// check also in request body
|
|
|
|
givenKey = req.body.api_key || req.body.map_key;
|
|
|
|
}
|
|
|
|
if ( ! givenKey ) {
|
2018-02-08 01:20:56 +08:00
|
|
|
return callback(null, false); // no api key, no authorization...
|
2015-07-13 21:05:03 +08:00
|
|
|
}
|
|
|
|
|
2018-02-08 01:20:56 +08:00
|
|
|
this.metadataBackend.getApikey(user, givenKey, (err, apikey) => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
2015-07-13 21:05:03 +08:00
|
|
|
}
|
2018-02-08 01:20:56 +08:00
|
|
|
if ( !isValidApiKey(apikey)) {
|
|
|
|
return callback(null, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return callback(null, true);
|
|
|
|
});
|
2015-07-13 21:05:03 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check access authorization
|
|
|
|
*
|
|
|
|
* @param req - standard req object. Importantly contains table and host information
|
2017-10-05 18:44:03 +08:00
|
|
|
* @param res - standard res object. Contains the auth parameters in locals
|
2015-07-13 21:05:03 +08:00
|
|
|
* @param callback function(err, allowed) is access allowed not?
|
|
|
|
*/
|
2017-10-05 17:28:41 +08:00
|
|
|
AuthApi.prototype.authorize = function(req, res, callback) {
|
2015-07-13 21:05:03 +08:00
|
|
|
var self = this;
|
2017-10-05 17:28:41 +08:00
|
|
|
var user = res.locals.user;
|
2015-07-13 21:05:03 +08:00
|
|
|
|
|
|
|
step(
|
|
|
|
function () {
|
|
|
|
self.authorizedByAPIKey(user, req, this);
|
|
|
|
},
|
|
|
|
function checkApiKey(err, authorized){
|
2017-03-31 02:31:53 +08:00
|
|
|
req.profiler.done('authorizedByAPIKey');
|
2015-07-13 21:05:03 +08:00
|
|
|
assert.ifError(err);
|
|
|
|
|
|
|
|
// if not authorized by api_key, continue
|
|
|
|
if (!authorized) {
|
|
|
|
// not authorized by api_key, check if authorized by signer
|
2017-10-05 17:28:41 +08:00
|
|
|
return self.authorizedBySigner(res, this);
|
2015-07-13 21:05:03 +08:00
|
|
|
}
|
|
|
|
|
2018-02-08 00:14:13 +08:00
|
|
|
const asMaster = false;
|
2015-07-13 21:05:03 +08:00
|
|
|
// authorized by api key, login as the given username and stop
|
2018-02-08 00:14:13 +08:00
|
|
|
self.pgConnection.setDBAuth(user, res.locals, asMaster, function(err) {
|
2015-07-13 21:05:03 +08:00
|
|
|
callback(err, true); // authorized (or error)
|
|
|
|
});
|
|
|
|
},
|
|
|
|
function checkSignAuthorized(err, authorized) {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! authorized ) {
|
|
|
|
// request not authorized by signer.
|
|
|
|
|
|
|
|
// if no signer name was given, let dbparams and
|
|
|
|
// PostgreSQL do the rest.
|
|
|
|
//
|
2017-10-05 17:28:41 +08:00
|
|
|
if ( ! res.locals.signer ) {
|
2015-07-13 21:05:03 +08:00
|
|
|
return callback(null, true); // authorized so far
|
|
|
|
}
|
|
|
|
|
|
|
|
// if signer name was given, return no authorization
|
|
|
|
return callback(null, false);
|
|
|
|
}
|
|
|
|
|
2018-02-08 00:14:13 +08:00
|
|
|
const asMaster = true;
|
|
|
|
self.pgConnection.setDBAuth(user, res.locals, asMaster, function(err) {
|
2017-03-31 02:31:53 +08:00
|
|
|
req.profiler.done('setDBAuth');
|
2015-07-13 21:05:03 +08:00
|
|
|
callback(err, true); // authorized (or error)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
};
|