From 963737d3fba2423eae3225da32cc48ef06aa81c7 Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Thu, 15 Feb 2018 11:36:42 +0100 Subject: [PATCH 1/9] create lib for getting api key token from request --- .../api/get_api_key_token_from_request.js | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 lib/cartodb/api/get_api_key_token_from_request.js diff --git a/lib/cartodb/api/get_api_key_token_from_request.js b/lib/cartodb/api/get_api_key_token_from_request.js new file mode 100644 index 00000000..6173b7c6 --- /dev/null +++ b/lib/cartodb/api/get_api_key_token_from_request.js @@ -0,0 +1,62 @@ +'use strict'; + +const basicAuth = require('basic-auth'); + +module.exports = function getApiKeyTokenFromRequest(req) { + let apiKeyToken = null; + + for (var getter of apiKeyGetters) { + (apiKeyToken = getter(req)); + if (apiKeyTokenFound(apiKeyToken)) { + break; + } + } + + return apiKeyToken; +}; + +//-------------------------------------------------------------------------------- + +const apiKeyGetters = [ + getApikeyTokenFromHeaderAuthorization, + getApikeyTokenFromRequestQueryString, + getApikeyTokenFromRequestBody, +]; + +function getApikeyTokenFromHeaderAuthorization(req) { + const credentials = basicAuth(req); + + if (credentials) { + return credentials.pass; + } else { + return null; + } +} + +function getApikeyTokenFromRequestQueryString(req) { + if (req.query.api_key) { + return req.query.api_key; + } + + if (req.query.map_key) { + return req.query.map_key; + } + + return null; +} + +function getApikeyTokenFromRequestBody(req) { + if (req.body && req.body.api_key) { + return req.body.api_key; + } + + if (req.body && req.body.map_key) { + return req.body.map_key; + } + + return null; +} + +function apiKeyTokenFound(apiKeyToken) { + return !!apiKeyToken; +} From 5db0e9c8d8aba2c50882a92c4da38f9f96651058 Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Thu, 15 Feb 2018 12:50:42 +0100 Subject: [PATCH 2/9] add middleware for apikeyToken --- lib/cartodb/api/auth_api.js | 17 +++++------- lib/cartodb/backends/pg_connection.js | 2 +- lib/cartodb/controllers/named_maps_admin.js | 2 +- .../middleware/context/apikey-token.js | 9 +++++++ lib/cartodb/middleware/context/index.js | 2 ++ .../lib}/get_api_key_token_from_request.js | 2 +- package.json | 1 + test/unit/cartodb/prepare-context.test.js | 26 +++++++++++++++++++ yarn.lock | 6 +++++ 9 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 lib/cartodb/middleware/context/apikey-token.js rename lib/cartodb/{api => middleware/lib}/get_api_key_token_from_request.js (97%) diff --git a/lib/cartodb/api/auth_api.js b/lib/cartodb/api/auth_api.js index ca4c2724..22aca1ca 100644 --- a/lib/cartodb/api/auth_api.js +++ b/lib/cartodb/api/auth_api.js @@ -54,21 +54,18 @@ function isValidApiKey(apikey) { // Check if a request is authorized by api_key // // @param user -// @param req express request object +// @param res express response 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 ) { +AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { + const apikeyToken = res.locals.apikeyToken; + + if ( ! apikeyToken ) { return callback(null, false); // no api key, no authorization... } - this.metadataBackend.getApikey(user, givenKey, (err, apikey) => { + this.metadataBackend.getApikey(user, apikeyToken, (err, apikey) => { if (err) { return callback(err); } @@ -104,7 +101,7 @@ AuthApi.prototype.authorizedByAPIKey = function(user, req, callback) { AuthApi.prototype.authorize = function(req, res, callback) { var user = res.locals.user; - this.authorizedByAPIKey(user, req, (err, isAuthorizedByApikey) => { + this.authorizedByAPIKey(user, res, (err, isAuthorizedByApikey) => { if (err) { return callback(err); } diff --git a/lib/cartodb/backends/pg_connection.js b/lib/cartodb/backends/pg_connection.js index a145d0d2..37023c90 100644 --- a/lib/cartodb/backends/pg_connection.js +++ b/lib/cartodb/backends/pg_connection.js @@ -31,7 +31,7 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba return callback(); }); } else if (apikeyType === 'regular') { - this.metadataBackend.getApikey(username, params.api_key || params.map_key, (err, apikey) => { + this.metadataBackend.getApikey(username, params.apikeyToken, (err, apikey) => { if (err) { return callback(err); } diff --git a/lib/cartodb/controllers/named_maps_admin.js b/lib/cartodb/controllers/named_maps_admin.js index a4d05467..5839e147 100644 --- a/lib/cartodb/controllers/named_maps_admin.js +++ b/lib/cartodb/controllers/named_maps_admin.js @@ -70,7 +70,7 @@ NamedMapsAdminController.prototype.authorizedByAPIKey = function (action, label) return function authorizedByAPIKeyMiddleware (req, res, next) { const { user } = res.locals; - this.authApi.authorizedByAPIKey(user, req, (err, authenticated) => { + this.authApi.authorizedByAPIKey(user, res, (err, authenticated) => { if (err) { return next(err); } diff --git a/lib/cartodb/middleware/context/apikey-token.js b/lib/cartodb/middleware/context/apikey-token.js new file mode 100644 index 00000000..f18cf60a --- /dev/null +++ b/lib/cartodb/middleware/context/apikey-token.js @@ -0,0 +1,9 @@ +'use strict'; + +const getApikeyTokenFromRequest = require('../lib/get_api_key_token_from_request'); + +module.exports = () => function apikeyTokenMiddleware(req, res, next) { + res.locals.apikeyToken = getApikeyTokenFromRequest(req); + + return next(); +}; diff --git a/lib/cartodb/middleware/context/index.js b/lib/cartodb/middleware/context/index.js index 640aafd6..96b261a4 100644 --- a/lib/cartodb/middleware/context/index.js +++ b/lib/cartodb/middleware/context/index.js @@ -1,6 +1,7 @@ const locals = require('./locals'); const cleanUpQueryParams = require('./clean-up-query-params'); const layergroupToken = require('./layergroup-token'); +const apikeyToken = require('./apikey-token'); const authorize = require('./authorize'); const dbConnSetup = require('./db-conn-setup'); @@ -9,6 +10,7 @@ module.exports = function prepareContextMiddleware(authApi, pgConnection) { locals, cleanUpQueryParams(), layergroupToken, + apikeyToken(), authorize(authApi), dbConnSetup(pgConnection) ]; diff --git a/lib/cartodb/api/get_api_key_token_from_request.js b/lib/cartodb/middleware/lib/get_api_key_token_from_request.js similarity index 97% rename from lib/cartodb/api/get_api_key_token_from_request.js rename to lib/cartodb/middleware/lib/get_api_key_token_from_request.js index 6173b7c6..5fbc74c2 100644 --- a/lib/cartodb/api/get_api_key_token_from_request.js +++ b/lib/cartodb/middleware/lib/get_api_key_token_from_request.js @@ -6,7 +6,7 @@ module.exports = function getApiKeyTokenFromRequest(req) { let apiKeyToken = null; for (var getter of apiKeyGetters) { - (apiKeyToken = getter(req)); + apiKeyToken = getter(req); if (apiKeyTokenFound(apiKeyToken)) { break; } diff --git a/package.json b/package.json index 563aca4c..b2dc6652 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "Simon Martin " ], "dependencies": { + "basic-auth": "^2.0.0", "body-parser": "^1.18.2", "camshaft": "0.61.2", "cartodb-psql": "0.10.2", diff --git a/test/unit/cartodb/prepare-context.test.js b/test/unit/cartodb/prepare-context.test.js index 61ba0c55..acb7707e 100644 --- a/test/unit/cartodb/prepare-context.test.js +++ b/test/unit/cartodb/prepare-context.test.js @@ -10,6 +10,7 @@ var TemplateMaps = require('../../../lib/cartodb/backends/template_maps'); const cleanUpQueryParamsMiddleware = require('../../../lib/cartodb/middleware/context/clean-up-query-params'); const authorizeMiddleware = require('../../../lib/cartodb/middleware/context/authorize'); const dbConnSetupMiddleware = require('../../../lib/cartodb/middleware/context/db-conn-setup'); +const apikeyTokenMiddleware = require('../../../lib/cartodb/middleware/context/apikey-token'); const localsMiddleware = require('../../../lib/cartodb/middleware/context/locals'); var windshaft = require('windshaft'); @@ -23,6 +24,7 @@ describe('prepare-context', function() { let cleanUpQueryParams; let dbConnSetup; let authorize; + let setApikeyToken; before(function() { var redisPool = new RedisPool(global.environment.redis); @@ -35,6 +37,7 @@ describe('prepare-context', function() { cleanUpQueryParams = cleanUpQueryParamsMiddleware(); authorize = authorizeMiddleware(authApi); dbConnSetup = dbConnSetupMiddleware(pgConnection); + setApikeyToken = apikeyTokenMiddleware(); }); @@ -180,4 +183,27 @@ describe('prepare-context', function() { }); }); + describe.only('Set apikey token', function(){ + it('from query param', function (done) { + var req = { + headers: { + host: 'localhost' + }, + query: { + api_quey: '1234', + } + }; + var res = {}; + setApikeyToken(prepareRequest(req), prepareResponse(res), function (err) { + if (err) { + return done(err); + } + var query = res.locals; + console.log(query); + + assert.equal('1234', query.apikeyToken); + done(); + }); + }); + }); }); diff --git a/yarn.lock b/yarn.lock index d8a290a4..c556c94e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -143,6 +143,12 @@ balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" +basic-auth@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" + dependencies: + safe-buffer "5.1.1" + bcrypt-pbkdf@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" From 140441b777c9a2f619487c1b477a41b9850f069c Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Thu, 15 Feb 2018 12:53:01 +0100 Subject: [PATCH 3/9] fix test --- test/unit/cartodb/prepare-context.test.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/unit/cartodb/prepare-context.test.js b/test/unit/cartodb/prepare-context.test.js index acb7707e..cc58be4c 100644 --- a/test/unit/cartodb/prepare-context.test.js +++ b/test/unit/cartodb/prepare-context.test.js @@ -183,14 +183,14 @@ describe('prepare-context', function() { }); }); - describe.only('Set apikey token', function(){ + describe('Set apikey token', function(){ it('from query param', function (done) { var req = { headers: { host: 'localhost' }, query: { - api_quey: '1234', + api_key: '1234', } }; var res = {}; @@ -199,7 +199,6 @@ describe('prepare-context', function() { return done(err); } var query = res.locals; - console.log(query); assert.equal('1234', query.apikeyToken); done(); From fc420c2c0f123ff372022471e12a78ca8309f5c1 Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Thu, 15 Feb 2018 15:19:09 +0100 Subject: [PATCH 4/9] use for compatibility res.locals.api_key instead of res.locals.apikeyToken --- lib/cartodb/api/auth_api.js | 2 +- lib/cartodb/backends/pg_connection.js | 2 +- lib/cartodb/middleware/context/apikey-token.js | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/cartodb/api/auth_api.js b/lib/cartodb/api/auth_api.js index 22aca1ca..9b24a16e 100644 --- a/lib/cartodb/api/auth_api.js +++ b/lib/cartodb/api/auth_api.js @@ -59,7 +59,7 @@ function isValidApiKey(apikey) { // NOTE: authorized is expected to be 0 or 1 (integer) // AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { - const apikeyToken = res.locals.apikeyToken; + const apikeyToken = res.locals.api_key; if ( ! apikeyToken ) { return callback(null, false); // no api key, no authorization... diff --git a/lib/cartodb/backends/pg_connection.js b/lib/cartodb/backends/pg_connection.js index 37023c90..b7d81721 100644 --- a/lib/cartodb/backends/pg_connection.js +++ b/lib/cartodb/backends/pg_connection.js @@ -31,7 +31,7 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba return callback(); }); } else if (apikeyType === 'regular') { - this.metadataBackend.getApikey(username, params.apikeyToken, (err, apikey) => { + this.metadataBackend.getApikey(username, params.api_key, (err, apikey) => { if (err) { return callback(err); } diff --git a/lib/cartodb/middleware/context/apikey-token.js b/lib/cartodb/middleware/context/apikey-token.js index f18cf60a..db43d843 100644 --- a/lib/cartodb/middleware/context/apikey-token.js +++ b/lib/cartodb/middleware/context/apikey-token.js @@ -3,7 +3,6 @@ const getApikeyTokenFromRequest = require('../lib/get_api_key_token_from_request'); module.exports = () => function apikeyTokenMiddleware(req, res, next) { - res.locals.apikeyToken = getApikeyTokenFromRequest(req); - + res.locals.api_key = getApikeyTokenFromRequest(req); return next(); }; From 3e916c6054ba7c3c210f539969a8be31530c11f5 Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Thu, 15 Feb 2018 15:20:05 +0100 Subject: [PATCH 5/9] check if req.query exist before getting req.query.api_key/map_key --- lib/cartodb/middleware/lib/get_api_key_token_from_request.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cartodb/middleware/lib/get_api_key_token_from_request.js b/lib/cartodb/middleware/lib/get_api_key_token_from_request.js index 5fbc74c2..3da6f1d6 100644 --- a/lib/cartodb/middleware/lib/get_api_key_token_from_request.js +++ b/lib/cartodb/middleware/lib/get_api_key_token_from_request.js @@ -34,11 +34,11 @@ function getApikeyTokenFromHeaderAuthorization(req) { } function getApikeyTokenFromRequestQueryString(req) { - if (req.query.api_key) { + if (req.query && req.query.api_key) { return req.query.api_key; } - if (req.query.map_key) { + if (req.query && req.query.map_key) { return req.query.map_key; } From 18dbeea003cb323d7b4e4e21dadbff808bcd69a1 Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Thu, 15 Feb 2018 15:20:52 +0100 Subject: [PATCH 6/9] get apikey token from request in named maps admin middleware --- lib/cartodb/controllers/named_maps_admin.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/cartodb/controllers/named_maps_admin.js b/lib/cartodb/controllers/named_maps_admin.js index 5839e147..fe484f7f 100644 --- a/lib/cartodb/controllers/named_maps_admin.js +++ b/lib/cartodb/controllers/named_maps_admin.js @@ -1,6 +1,13 @@ const { templateName } = require('../backends/template_maps'); const cors = require('../middleware/cors'); const userMiddleware = require('../middleware/user'); +const localsMiddleware = require('../middleware/context/locals'); +const apikeyTokenMiddleware = require('../middleware/context/apikey-token'); + +const apikeyMiddleware = [ + localsMiddleware, + apikeyTokenMiddleware(), +]; /** * @param {AuthApi} authApi @@ -22,6 +29,7 @@ NamedMapsAdminController.prototype.register = function (app) { `${base_url_templated}/`, cors(), userMiddleware, + apikeyMiddleware, this.checkContentType('POST', 'POST TEMPLATE'), this.authorizedByAPIKey('create', 'POST TEMPLATE'), this.create() @@ -31,6 +39,7 @@ NamedMapsAdminController.prototype.register = function (app) { `${base_url_templated}/:template_id`, cors(), userMiddleware, + apikeyMiddleware, this.checkContentType('PUT', 'PUT TEMPLATE'), this.authorizedByAPIKey('update', 'PUT TEMPLATE'), this.update() @@ -40,6 +49,7 @@ NamedMapsAdminController.prototype.register = function (app) { `${base_url_templated}/:template_id`, cors(), userMiddleware, + apikeyMiddleware, this.authorizedByAPIKey('get', 'GET TEMPLATE'), this.retrieve() ); @@ -48,6 +58,7 @@ NamedMapsAdminController.prototype.register = function (app) { `${base_url_templated}/:template_id`, cors(), userMiddleware, + apikeyMiddleware, this.authorizedByAPIKey('delete', 'DELETE TEMPLATE'), this.destroy() ); @@ -56,6 +67,7 @@ NamedMapsAdminController.prototype.register = function (app) { `${base_url_templated}/`, cors(), userMiddleware, + apikeyMiddleware, this.authorizedByAPIKey('list', 'GET TEMPLATE LIST'), this.list() ); @@ -69,7 +81,6 @@ NamedMapsAdminController.prototype.register = function (app) { NamedMapsAdminController.prototype.authorizedByAPIKey = function (action, label) { return function authorizedByAPIKeyMiddleware (req, res, next) { const { user } = res.locals; - this.authApi.authorizedByAPIKey(user, res, (err, authenticated) => { if (err) { return next(err); From 11aa4d12bd64d37a619dbbd1911d9e148eb22f24 Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Thu, 15 Feb 2018 15:27:41 +0100 Subject: [PATCH 7/9] add tests for getting api key token from requests --- test/unit/cartodb/prepare-context.test.js | 42 ++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/test/unit/cartodb/prepare-context.test.js b/test/unit/cartodb/prepare-context.test.js index cc58be4c..eabad095 100644 --- a/test/unit/cartodb/prepare-context.test.js +++ b/test/unit/cartodb/prepare-context.test.js @@ -200,7 +200,47 @@ describe('prepare-context', function() { } var query = res.locals; - assert.equal('1234', query.apikeyToken); + assert.equal('1234', query.api_key); + done(); + }); + }); + + it('from body param', function (done) { + var req = { + headers: { + host: 'localhost' + }, + body: { + api_key: '1234', + } + }; + var res = {}; + setApikeyToken(prepareRequest(req), prepareResponse(res), function (err) { + if (err) { + return done(err); + } + var query = res.locals; + + assert.equal('1234', query.api_key); + done(); + }); + }); + + it('from http header', function (done) { + var req = { + headers: { + host: 'localhost', + authorization: 'Basic dXNlcjoxMjM0', // user: user, password: 1234 + } + }; + var res = {}; + setApikeyToken(prepareRequest(req), prepareResponse(res), function (err) { + if (err) { + return done(err); + } + var query = res.locals; + + assert.equal('1234', query.api_key); done(); }); }); From cda2616a8a4eeae7f4dd2a78f1b431e94c65b954 Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Thu, 15 Feb 2018 17:49:47 +0100 Subject: [PATCH 8/9] get and check api key credentials from api key: username and token --- lib/cartodb/api/auth_api.js | 10 +++ lib/cartodb/controllers/named_maps_admin.js | 4 +- .../middleware/context/apikey-credentials.js | 10 +++ .../middleware/context/apikey-token.js | 8 -- lib/cartodb/middleware/context/index.js | 4 +- .../get_api_key_credentials_from_request.js | 77 +++++++++++++++++++ .../lib/get_api_key_token_from_request.js | 62 --------------- test/unit/cartodb/prepare-context.test.js | 33 ++++++-- 8 files changed, 127 insertions(+), 81 deletions(-) create mode 100644 lib/cartodb/middleware/context/apikey-credentials.js delete mode 100644 lib/cartodb/middleware/context/apikey-token.js create mode 100644 lib/cartodb/middleware/lib/get_api_key_credentials_from_request.js delete mode 100644 lib/cartodb/middleware/lib/get_api_key_token_from_request.js diff --git a/lib/cartodb/api/auth_api.js b/lib/cartodb/api/auth_api.js index 9b24a16e..ef874483 100644 --- a/lib/cartodb/api/auth_api.js +++ b/lib/cartodb/api/auth_api.js @@ -60,6 +60,7 @@ function isValidApiKey(apikey) { // AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { const apikeyToken = res.locals.api_key; + const apikeyUsername = res.locals.apikeyUsername; if ( ! apikeyToken ) { return callback(null, false); // no api key, no authorization... @@ -78,6 +79,15 @@ AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { return callback(error); } + if (apikeyUsername && (apikeyUsername !== res.locals.user)) { + const error = new Error('Forbidden'); + error.type = 'auth'; + error.subtype = 'api-key-username-mismatch'; + error.http_status = 403; + + return callback(error); + } + if (!apikey.grantsMaps) { const error = new Error('Forbidden'); error.type = 'auth'; diff --git a/lib/cartodb/controllers/named_maps_admin.js b/lib/cartodb/controllers/named_maps_admin.js index fe484f7f..b1c6a451 100644 --- a/lib/cartodb/controllers/named_maps_admin.js +++ b/lib/cartodb/controllers/named_maps_admin.js @@ -2,11 +2,11 @@ const { templateName } = require('../backends/template_maps'); const cors = require('../middleware/cors'); const userMiddleware = require('../middleware/user'); const localsMiddleware = require('../middleware/context/locals'); -const apikeyTokenMiddleware = require('../middleware/context/apikey-token'); +const apikeyCredentialsMiddleware = require('../middleware/context/apikey-credentials'); const apikeyMiddleware = [ localsMiddleware, - apikeyTokenMiddleware(), + apikeyCredentialsMiddleware(), ]; /** diff --git a/lib/cartodb/middleware/context/apikey-credentials.js b/lib/cartodb/middleware/context/apikey-credentials.js new file mode 100644 index 00000000..820bb8c6 --- /dev/null +++ b/lib/cartodb/middleware/context/apikey-credentials.js @@ -0,0 +1,10 @@ +'use strict'; + +const getApikeyCredentialsFromRequest = require('../lib/get_api_key_credentials_from_request'); + +module.exports = () => function apikeyTokenMiddleware(req, res, next) { + const apikeyCredentials = getApikeyCredentialsFromRequest(req); + res.locals.api_key = apikeyCredentials.token; + res.locals.apikeyUsername = apikeyCredentials.username; + return next(); +}; diff --git a/lib/cartodb/middleware/context/apikey-token.js b/lib/cartodb/middleware/context/apikey-token.js deleted file mode 100644 index db43d843..00000000 --- a/lib/cartodb/middleware/context/apikey-token.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -const getApikeyTokenFromRequest = require('../lib/get_api_key_token_from_request'); - -module.exports = () => function apikeyTokenMiddleware(req, res, next) { - res.locals.api_key = getApikeyTokenFromRequest(req); - return next(); -}; diff --git a/lib/cartodb/middleware/context/index.js b/lib/cartodb/middleware/context/index.js index 96b261a4..8922739f 100644 --- a/lib/cartodb/middleware/context/index.js +++ b/lib/cartodb/middleware/context/index.js @@ -1,7 +1,7 @@ const locals = require('./locals'); const cleanUpQueryParams = require('./clean-up-query-params'); const layergroupToken = require('./layergroup-token'); -const apikeyToken = require('./apikey-token'); +const apikeyCredentials = require('./apikey-credentials'); const authorize = require('./authorize'); const dbConnSetup = require('./db-conn-setup'); @@ -10,7 +10,7 @@ module.exports = function prepareContextMiddleware(authApi, pgConnection) { locals, cleanUpQueryParams(), layergroupToken, - apikeyToken(), + apikeyCredentials(), authorize(authApi), dbConnSetup(pgConnection) ]; diff --git a/lib/cartodb/middleware/lib/get_api_key_credentials_from_request.js b/lib/cartodb/middleware/lib/get_api_key_credentials_from_request.js new file mode 100644 index 00000000..397e972b --- /dev/null +++ b/lib/cartodb/middleware/lib/get_api_key_credentials_from_request.js @@ -0,0 +1,77 @@ +'use strict'; + +const basicAuth = require('basic-auth'); + +module.exports = function getApiKeyCredentialsFromRequest(req) { + let apikeyCredentials = { + token: null, + username: null, + }; + + for (var getter of apikeyGetters) { + apikeyCredentials = getter(req); + if (apikeyTokenFound(apikeyCredentials)) { + break; + } + } + + return apikeyCredentials; +}; + +//-------------------------------------------------------------------------------- + +const apikeyGetters = [ + getApikeyTokenFromHeaderAuthorization, + getApikeyTokenFromRequestQueryString, + getApikeyTokenFromRequestBody, +]; + +function getApikeyTokenFromHeaderAuthorization(req) { + const credentials = basicAuth(req); + + if (credentials) { + return { + username: credentials.username, + token: credentials.pass + }; + } else { + return { + username: null, + token: null, + }; + } +} + +function getApikeyTokenFromRequestQueryString(req) { + let token = null; + + if (req.query && req.query.api_key) { + token = req.query.api_key; + } else if (req.query && req.query.map_key) { + token = req.query.map_key; + } + + return { + username: null, + token: token, + }; +} + +function getApikeyTokenFromRequestBody(req) { + let token = null; + + if (req.body && req.body.api_key) { + token = req.body.api_key; + } else if (req.body && req.body.map_key) { + token = req.body.map_key; + } + + return { + username: null, + token: token, + }; +} + +function apikeyTokenFound(apikey) { + return !!apikey && !!apikey.token; +} diff --git a/lib/cartodb/middleware/lib/get_api_key_token_from_request.js b/lib/cartodb/middleware/lib/get_api_key_token_from_request.js deleted file mode 100644 index 3da6f1d6..00000000 --- a/lib/cartodb/middleware/lib/get_api_key_token_from_request.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -const basicAuth = require('basic-auth'); - -module.exports = function getApiKeyTokenFromRequest(req) { - let apiKeyToken = null; - - for (var getter of apiKeyGetters) { - apiKeyToken = getter(req); - if (apiKeyTokenFound(apiKeyToken)) { - break; - } - } - - return apiKeyToken; -}; - -//-------------------------------------------------------------------------------- - -const apiKeyGetters = [ - getApikeyTokenFromHeaderAuthorization, - getApikeyTokenFromRequestQueryString, - getApikeyTokenFromRequestBody, -]; - -function getApikeyTokenFromHeaderAuthorization(req) { - const credentials = basicAuth(req); - - if (credentials) { - return credentials.pass; - } else { - return null; - } -} - -function getApikeyTokenFromRequestQueryString(req) { - if (req.query && req.query.api_key) { - return req.query.api_key; - } - - if (req.query && req.query.map_key) { - return req.query.map_key; - } - - return null; -} - -function getApikeyTokenFromRequestBody(req) { - if (req.body && req.body.api_key) { - return req.body.api_key; - } - - if (req.body && req.body.map_key) { - return req.body.map_key; - } - - return null; -} - -function apiKeyTokenFound(apiKeyToken) { - return !!apiKeyToken; -} diff --git a/test/unit/cartodb/prepare-context.test.js b/test/unit/cartodb/prepare-context.test.js index eabad095..61d7b514 100644 --- a/test/unit/cartodb/prepare-context.test.js +++ b/test/unit/cartodb/prepare-context.test.js @@ -10,7 +10,7 @@ var TemplateMaps = require('../../../lib/cartodb/backends/template_maps'); const cleanUpQueryParamsMiddleware = require('../../../lib/cartodb/middleware/context/clean-up-query-params'); const authorizeMiddleware = require('../../../lib/cartodb/middleware/context/authorize'); const dbConnSetupMiddleware = require('../../../lib/cartodb/middleware/context/db-conn-setup'); -const apikeyTokenMiddleware = require('../../../lib/cartodb/middleware/context/apikey-token'); +const apikeyCredentialsMiddleware = require('../../../lib/cartodb/middleware/context/apikey-credentials'); const localsMiddleware = require('../../../lib/cartodb/middleware/context/locals'); var windshaft = require('windshaft'); @@ -24,7 +24,7 @@ describe('prepare-context', function() { let cleanUpQueryParams; let dbConnSetup; let authorize; - let setApikeyToken; + let setApikeyCredentials; before(function() { var redisPool = new RedisPool(global.environment.redis); @@ -37,7 +37,7 @@ describe('prepare-context', function() { cleanUpQueryParams = cleanUpQueryParamsMiddleware(); authorize = authorizeMiddleware(authApi); dbConnSetup = dbConnSetupMiddleware(pgConnection); - setApikeyToken = apikeyTokenMiddleware(); + setApikeyCredentials = apikeyCredentialsMiddleware(); }); @@ -194,7 +194,7 @@ describe('prepare-context', function() { } }; var res = {}; - setApikeyToken(prepareRequest(req), prepareResponse(res), function (err) { + setApikeyCredentials(prepareRequest(req), prepareResponse(res), function (err) { if (err) { return done(err); } @@ -215,7 +215,7 @@ describe('prepare-context', function() { } }; var res = {}; - setApikeyToken(prepareRequest(req), prepareResponse(res), function (err) { + setApikeyCredentials(prepareRequest(req), prepareResponse(res), function (err) { if (err) { return done(err); } @@ -230,11 +230,30 @@ describe('prepare-context', function() { var req = { headers: { host: 'localhost', - authorization: 'Basic dXNlcjoxMjM0', // user: user, password: 1234 + authorization: 'Basic bG9jYWxob3N0OjEyMzQ=', // user: localhost, password: 1234 } }; var res = {}; - setApikeyToken(prepareRequest(req), prepareResponse(res), function (err) { + setApikeyCredentials(prepareRequest(req), prepareResponse(res), function (err) { + if (err) { + return done(err); + } + var query = res.locals; + + assert.equal('1234', query.api_key); + done(); + }); + }); + + it('fail from http header with user mismatch', function (done) { + var req = { + headers: { + host: 'localhost', + authorization: 'Basic YW5vdGhlcl91c2VyOjEyMzQ=', // user: another_user, password: 1234 + } + }; + var res = {}; + setApikeyCredentials(prepareRequest(req), prepareResponse(res), function (err) { if (err) { return done(err); } From e84d88b7a35378042ccdf9a9aed85d2da588f627 Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Thu, 15 Feb 2018 17:53:15 +0100 Subject: [PATCH 9/9] remove test --- test/unit/cartodb/prepare-context.test.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/test/unit/cartodb/prepare-context.test.js b/test/unit/cartodb/prepare-context.test.js index 61d7b514..2eb7e890 100644 --- a/test/unit/cartodb/prepare-context.test.js +++ b/test/unit/cartodb/prepare-context.test.js @@ -244,24 +244,5 @@ describe('prepare-context', function() { done(); }); }); - - it('fail from http header with user mismatch', function (done) { - var req = { - headers: { - host: 'localhost', - authorization: 'Basic YW5vdGhlcl91c2VyOjEyMzQ=', // user: another_user, password: 1234 - } - }; - var res = {}; - setApikeyCredentials(prepareRequest(req), prepareResponse(res), function (err) { - if (err) { - return done(err); - } - var query = res.locals; - - assert.equal('1234', query.api_key); - done(); - }); - }); }); });