merge conflicts
This commit is contained in:
commit
81f44f2935
@ -23,6 +23,7 @@ var express= require('express')
|
|||||||
, Meta = require(global.settings.app_root + '/app/models/metadata')
|
, Meta = require(global.settings.app_root + '/app/models/metadata')
|
||||||
, oAuth = require(global.settings.app_root + '/app/models/oauth')
|
, oAuth = require(global.settings.app_root + '/app/models/oauth')
|
||||||
, PSQL = require(global.settings.app_root + '/app/models/psql')
|
, PSQL = require(global.settings.app_root + '/app/models/psql')
|
||||||
|
, ApiKeyAuth = require(global.settings.app_root + '/app/models/apikey_auth')
|
||||||
, _ = require('underscore');
|
, _ = require('underscore');
|
||||||
|
|
||||||
app.use(express.bodyParser());
|
app.use(express.bodyParser());
|
||||||
@ -35,6 +36,7 @@ function handleQuery(req, res){
|
|||||||
// sanitize input
|
// sanitize input
|
||||||
var body = (req.body) ? req.body : {};
|
var body = (req.body) ? req.body : {};
|
||||||
var sql = req.query.q || body.q; // get and post
|
var sql = req.query.q || body.q; // get and post
|
||||||
|
var api_key = req.query.api_key || body.api_key;
|
||||||
var database = req.query.database; // deprecate this in future
|
var database = req.query.database; // deprecate this in future
|
||||||
var limit = parseInt(req.query.rows_per_page);
|
var limit = parseInt(req.query.rows_per_page);
|
||||||
var offset = parseInt(req.query.page);
|
var offset = parseInt(req.query.page);
|
||||||
@ -68,7 +70,11 @@ function handleQuery(req, res){
|
|||||||
function setDBGetUser(err, data) {
|
function setDBGetUser(err, data) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
database = (data == "" || _.isNull(data)) ? database : data;
|
database = (data == "" || _.isNull(data)) ? database : data;
|
||||||
|
if(api_key) {
|
||||||
|
ApiKeyAuth.verifyRequest(req, this);
|
||||||
|
} else {
|
||||||
oAuth.verifyRequest(req, this);
|
oAuth.verifyRequest(req, this);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
function querySql(err, user_id){
|
function querySql(err, user_id){
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
114
app/models/apikey_auth.js
Normal file
114
app/models/apikey_auth.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* this module allows to auth user using an pregenerated api key
|
||||||
|
*/
|
||||||
|
|
||||||
|
var RedisPool = require("./redis_pool")
|
||||||
|
, _ = require('underscore')
|
||||||
|
, Step = require('step');
|
||||||
|
|
||||||
|
module.exports = (function() {
|
||||||
|
|
||||||
|
var me = {
|
||||||
|
user_metadata_db: 5,
|
||||||
|
table_metadata_db: 0,
|
||||||
|
user_key: "rails:users:<%= username %>",
|
||||||
|
map_key: "rails:users:<%= username %>:map_key",
|
||||||
|
table_key: "rails:<%= database_name %>:<%= table_name %>"
|
||||||
|
};
|
||||||
|
|
||||||
|
me.retrieve = function(db, redisKey, hashKey, callback) {
|
||||||
|
this.redisCmd(db,'HGET',[redisKey, hashKey], callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
me.inSet = function(db, setKey, member, callback) {
|
||||||
|
this.redisCmd(db,'SISMEMBER',[setKey, member], callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use Redis
|
||||||
|
*
|
||||||
|
* @param db - redis database number
|
||||||
|
* @param redisFunc - the redis function to execute
|
||||||
|
* @param redisArgs - the arguments for the redis function in an array
|
||||||
|
* @param callback - function to pass results too.
|
||||||
|
*/
|
||||||
|
me.redisCmd = function(db, redisFunc, redisArgs, callback) {
|
||||||
|
|
||||||
|
var redisClient;
|
||||||
|
Step(
|
||||||
|
function() {
|
||||||
|
var step = this;
|
||||||
|
RedisPool.acquire(db, function(_redisClient) {
|
||||||
|
redisClient = _redisClient;
|
||||||
|
redisArgs.push(step);
|
||||||
|
redisClient[redisFunc.toUpperCase()].apply(redisClient, redisArgs);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function releaseRedisClient(err, data) {
|
||||||
|
if (err) throw err;
|
||||||
|
RedisPool.release(db, redisClient);
|
||||||
|
callback(err, data);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user id for this particular subdomain/username
|
||||||
|
*
|
||||||
|
* @param req - standard express req object. importantly contains host information
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
me.getId = function(req, callback) {
|
||||||
|
// strip subdomain from header host
|
||||||
|
var username = req.headers.host.split('.')[0];
|
||||||
|
var redisKey = _.template(this.user_key, {username: username});
|
||||||
|
|
||||||
|
this.retrieve(this.user_metadata_db, redisKey, 'id', callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user map key for this particular subdomain/username
|
||||||
|
*
|
||||||
|
* @param req - standard express req object. importantly contains host information
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
me.checkAPIKey= function(req, callback) {
|
||||||
|
// strip subdomain from header host
|
||||||
|
var username = req.headers.host.split('.')[0];
|
||||||
|
var redisKey = _.template(this.map_key, {username: username});
|
||||||
|
var api_key = req.query.api_key || req.body.api_key;
|
||||||
|
this.inSet(this.user_metadata_db, redisKey, api_key, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get privacy for cartodb table
|
||||||
|
*
|
||||||
|
* @param req - standard req object. Importantly contains table and host information
|
||||||
|
* @param callback - user_id if ok, null if auth fails
|
||||||
|
*/
|
||||||
|
me.verifyRequest = function(req, callback) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
Step(
|
||||||
|
// check api key
|
||||||
|
function(){
|
||||||
|
that.checkAPIKey(req, this);
|
||||||
|
},
|
||||||
|
// get user id or fail
|
||||||
|
function (err, apikey_valid) {
|
||||||
|
if (apikey_valid) {
|
||||||
|
that.getId(req, this);
|
||||||
|
} else {
|
||||||
|
// no auth
|
||||||
|
callback(false, null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function (err, user_id){
|
||||||
|
if (err) throw err;
|
||||||
|
callback(false, user_id);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return me;
|
||||||
|
})();
|
@ -65,7 +65,7 @@ var oAuth = function(){
|
|||||||
me.verifyRequest = function(req, callback){
|
me.verifyRequest = function(req, callback){
|
||||||
var that = this;
|
var that = this;
|
||||||
//TODO: review this
|
//TODO: review this
|
||||||
var http = arguments['2'];
|
var http = true;//arguments['2'];
|
||||||
var passed_tokens;
|
var passed_tokens;
|
||||||
var ohash;
|
var ohash;
|
||||||
var signature;
|
var signature;
|
||||||
|
32
test/acceptance/app.auth.test.js
Normal file
32
test/acceptance/app.auth.test.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
require('../helper');
|
||||||
|
|
||||||
|
var app = require(global.settings.app_root + '/app/controllers/app')
|
||||||
|
, assert = require('assert')
|
||||||
|
, tests = module.exports = {}
|
||||||
|
, querystring = require('querystring');
|
||||||
|
|
||||||
|
tests['valid api key should allow insert in protected tables'] = function(){
|
||||||
|
assert.response(app, {
|
||||||
|
// view prepare_db.sh to see where to set api_key
|
||||||
|
url: "/api/v1/sql?api_key=1234&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('test')&database=cartodb_dev_user_1_db",
|
||||||
|
|
||||||
|
headers: {host: 'vizzuality.cartodb.com' },
|
||||||
|
method: 'GET'
|
||||||
|
},{
|
||||||
|
status: 200
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tests['invalid api key should NOT allow insert in protected tables'] = function(){
|
||||||
|
assert.response(app, {
|
||||||
|
// view prepare_db.sh to see where to set api_key
|
||||||
|
url: "/api/v1/sql?api_key=RAMBO&q=INSERT%20INTO%20private_table%20(name)%20VALUES%20('test')&database=cartodb_dev_user_1_db",
|
||||||
|
|
||||||
|
headers: {host: 'vizzuality.cartodb.com' },
|
||||||
|
method: 'GET'
|
||||||
|
},{
|
||||||
|
status: 400
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -24,7 +24,6 @@ app.setMaxListeners(0);
|
|||||||
var real_oauth_header = 'OAuth realm="http://vizzuality.testhost.lan/",oauth_consumer_key="fZeNGv5iYayvItgDYHUbot1Ukb5rVyX6QAg8GaY2",oauth_token="l0lPbtP68ao8NfStCiA3V3neqfM03JKhToxhUQTR",oauth_signature_method="HMAC-SHA1", oauth_signature="o4hx4hWP6KtLyFwggnYB4yPK8xI%3D",oauth_timestamp="1313581372",oauth_nonce="W0zUmvyC4eVL8cBd4YwlH1nnPTbxW0QBYcWkXTwe4",oauth_version="1.0"';
|
var real_oauth_header = 'OAuth realm="http://vizzuality.testhost.lan/",oauth_consumer_key="fZeNGv5iYayvItgDYHUbot1Ukb5rVyX6QAg8GaY2",oauth_token="l0lPbtP68ao8NfStCiA3V3neqfM03JKhToxhUQTR",oauth_signature_method="HMAC-SHA1", oauth_signature="o4hx4hWP6KtLyFwggnYB4yPK8xI%3D",oauth_timestamp="1313581372",oauth_nonce="W0zUmvyC4eVL8cBd4YwlH1nnPTbxW0QBYcWkXTwe4",oauth_version="1.0"';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tests['GET /api/v1/sql'] = function(){
|
tests['GET /api/v1/sql'] = function(){
|
||||||
assert.response(app, {
|
assert.response(app, {
|
||||||
url: '/api/v1/sql',
|
url: '/api/v1/sql',
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
echo "preparing redis..."
|
echo "preparing redis..."
|
||||||
echo "HSET rails:users:vizzuality id 1" | redis-cli -n 5
|
echo "HSET rails:users:vizzuality id 1" | redis-cli -n 5
|
||||||
echo "HSET rails:users:vizzuality database_name cartodb_test_user_1_db" | redis-cli -n 5
|
echo "HSET rails:users:vizzuality database_name cartodb_test_user_1_db" | redis-cli -n 5
|
||||||
|
echo "SADD rails:users:vizzuality:map_key 1234" | redis-cli -n 5
|
||||||
|
|
||||||
echo "preparing postgres..."
|
echo "preparing postgres..."
|
||||||
dropdb -Upostgres -hlocalhost cartodb_test_user_1_db
|
dropdb -Upostgres -hlocalhost cartodb_test_user_1_db
|
||||||
|
@ -62,8 +62,51 @@ ALTER TABLE ONLY untitle_table_4 ADD CONSTRAINT test_table_pkey PRIMARY KEY (car
|
|||||||
CREATE INDEX test_table_the_geom_idx ON untitle_table_4 USING gist (the_geom);
|
CREATE INDEX test_table_the_geom_idx ON untitle_table_4 USING gist (the_geom);
|
||||||
CREATE INDEX test_table_the_geom_webmercator_idx ON untitle_table_4 USING gist (the_geom_webmercator);
|
CREATE INDEX test_table_the_geom_webmercator_idx ON untitle_table_4 USING gist (the_geom_webmercator);
|
||||||
|
|
||||||
|
CREATE TABLE private_table (
|
||||||
|
updated_at timestamp without time zone DEFAULT now(),
|
||||||
|
created_at timestamp without time zone DEFAULT now(),
|
||||||
|
cartodb_id integer NOT NULL,
|
||||||
|
name character varying,
|
||||||
|
address character varying,
|
||||||
|
the_geom geometry,
|
||||||
|
the_geom_webmercator geometry,
|
||||||
|
CONSTRAINT enforce_dims_the_geom CHECK ((st_ndims(the_geom) = 2)),
|
||||||
|
CONSTRAINT enforce_dims_the_geom_webmercator CHECK ((st_ndims(the_geom_webmercator) = 2)),
|
||||||
|
CONSTRAINT enforce_geotype_the_geom CHECK (((geometrytype(the_geom) = 'POINT'::text) OR (the_geom IS NULL))),
|
||||||
|
CONSTRAINT enforce_geotype_the_geom_webmercator CHECK (((geometrytype(the_geom_webmercator) = 'POINT'::text) OR (the_geom_webmercator IS NULL))),
|
||||||
|
CONSTRAINT enforce_srid_the_geom CHECK ((st_srid(the_geom) = 4326)),
|
||||||
|
CONSTRAINT enforce_srid_the_geom_webmercator CHECK ((st_srid(the_geom_webmercator) = 3857))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE test_table_cartodb_id_seq_p
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
ALTER SEQUENCE test_table_cartodb_id_seq_p OWNED BY private_table.cartodb_id;
|
||||||
|
|
||||||
|
SELECT pg_catalog.setval('test_table_cartodb_id_seq_p', 60, true);
|
||||||
|
|
||||||
|
ALTER TABLE private_table ALTER COLUMN cartodb_id SET DEFAULT nextval('test_table_cartodb_id_seq_p'::regclass);
|
||||||
|
|
||||||
|
INSERT INTO private_table VALUES ('2011-09-21 14:02:21.358706', '2011-09-21 14:02:21.314252', 1, 'Hawai', 'Calle de Pérez Galdós 9, Madrid, Spain', '0101000020E6100000A6B73F170D990DC064E8D84125364440', '0101000020110F000076491621312319C122D4663F1DCC5241');
|
||||||
|
INSERT INTO private_table VALUES ('2011-09-21 14:02:21.358706', '2011-09-21 14:02:21.319101', 2, 'El Estocolmo', 'Calle de la Palma 72, Madrid, Spain', '0101000020E6100000C90567F0F7AB0DC0AB07CC43A6364440', '0101000020110F0000C4356B29423319C15DD1092DADCC5241');
|
||||||
|
INSERT INTO private_table VALUES ('2011-09-21 14:02:21.358706', '2011-09-21 14:02:21.324', 3, 'El Rey del Tallarín', 'Plaza Conde de Toreno 2, Madrid, Spain', '0101000020E610000021C8410933AD0DC0CB0EF10F5B364440', '0101000020110F000053E71AC64D3419C10F664E4659CC5241');
|
||||||
|
INSERT INTO private_table VALUES ('2011-09-21 14:02:21.358706', '2011-09-21 14:02:21.329509', 4, 'El Lacón', 'Manuel Fernández y González 8, Madrid, Spain', '0101000020E6100000BC5983F755990DC07D923B6C22354440', '0101000020110F00005DACDB056F2319C1EC41A980FCCA5241');
|
||||||
|
INSERT INTO private_table VALUES ('2011-09-21 14:02:21.358706', '2011-09-21 14:02:21.334931', 5, 'El Pico', 'Calle Divino Pastor 12, Madrid, Spain', '0101000020E61000003B6D8D08C6A10DC0371B2B31CF364440', '0101000020110F00005F716E91992A19C17DAAA4D6DACC5241');
|
||||||
|
|
||||||
|
ALTER TABLE ONLY private_table ADD CONSTRAINT test_table_pkey_p PRIMARY KEY (cartodb_id);
|
||||||
|
|
||||||
|
CREATE INDEX test_table_the_geom_idx_p ON private_table USING gist (the_geom);
|
||||||
|
CREATE INDEX test_table_the_geom_webmercator_idx_p ON private_table USING gist (the_geom_webmercator);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CREATE USER publicuser WITH PASSWORD '';
|
CREATE USER publicuser WITH PASSWORD '';
|
||||||
|
CREATE USER test_cartodb_user_1 WITH PASSWORD '';
|
||||||
|
|
||||||
GRANT SELECT ON TABLE untitle_table_4 TO publicuser;
|
GRANT SELECT ON TABLE untitle_table_4 TO publicuser;
|
||||||
|
GRANT ALL ON TABLE private_table TO test_cartodb_user_1;
|
||||||
|
GRANT ALL ON SEQUENCE test_table_cartodb_id_seq_p TO test_cartodb_user_1
|
||||||
|
Loading…
Reference in New Issue
Block a user