From 890f0d1ef64046b7ffe199ada8e53bcf2b4e0afd Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Wed, 14 Feb 2018 17:31:05 +0100 Subject: [PATCH 1/7] add fallback for using metadata fallback --- lib/cartodb/api/auth_api.js | 23 ++- lib/cartodb/backends/pg_connection.js | 24 +++ .../acceptance/auth/authorization-fallback.js | 159 ++++++++++++++++++ test/support/prepare_db.sh | 13 ++ test/support/test_helper.js | 1 + 5 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 test/acceptance/auth/authorization-fallback.js diff --git a/lib/cartodb/api/auth_api.js b/lib/cartodb/api/auth_api.js index ca4c2724..1ac2a1cc 100644 --- a/lib/cartodb/api/auth_api.js +++ b/lib/cartodb/api/auth_api.js @@ -1,3 +1,5 @@ +var _ = require('underscore'); // AUTH_FALLBACK + /** * * @param {PgConnection} pgConnection @@ -45,10 +47,10 @@ AuthApi.prototype.authorizedBySigner = function(res, callback) { }; function isValidApiKey(apikey) { - return apikey.type !== null && - apikey.user !== null && - apikey.databasePassword !== null && - apikey.databaseRole !== null; + return apikey.type && + apikey.user && + apikey.databasePassword && + apikey.databaseRole; } // Check if a request is authorized by api_key @@ -72,6 +74,19 @@ AuthApi.prototype.authorizedByAPIKey = function(user, req, callback) { if (err) { return callback(err); } + + //Remove this block when Auth fallback is not used anymore + // AUTH_FALLBACK + if (!apikey.databaseRole && apikey.user_id && global.environment.postgres_auth_user) { + apikey.databaseRole = _.template(global.environment.postgres_auth_user, apikey); + } + + //Remove this block when Auth fallback is not used anymore + // AUTH_FALLBACK + if (!apikey.databasePassword && global.environment.postgres.password) { + apikey.databasePassword = global.environment.postgres.password; + } + if ( !isValidApiKey(apikey)) { const error = new Error('Unauthorized'); error.type = 'auth'; diff --git a/lib/cartodb/backends/pg_connection.js b/lib/cartodb/backends/pg_connection.js index a145d0d2..d5d3ecdb 100644 --- a/lib/cartodb/backends/pg_connection.js +++ b/lib/cartodb/backends/pg_connection.js @@ -28,6 +28,12 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba params.dbuser = apikey.databaseRole; params.dbpassword = apikey.databasePassword; + //Remove this block when Auth fallback is not used anymore + // AUTH_FALLBACK + if (!params.dbuser && apikey.user_id && global.environment.postgres_auth_user) { + params.dbuser = _.template(global.environment.postgres_auth_user, apikey); + } + return callback(); }); } else if (apikeyType === 'regular') { @@ -39,6 +45,18 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba params.dbuser = apikey.databaseRole; params.dbpassword = apikey.databasePassword; + //Remove this block when Auth fallback is not used anymore + // AUTH_FALLBACK + if (!params.dbuser && apikey.user_id && apikey.type === 'master' && global.environment.postgres_auth_user) { + params.dbuser = _.template(global.environment.postgres_auth_user, apikey); + } + + //Remove this block when Auth fallback is not used anymore + // AUTH_FALLBACK + if (!params.dbpassword && global.environment.postgres.password) { + params.dbpassword = global.environment.postgres.password; + } + return callback(); }); } else if (apikeyType === 'default') { @@ -50,6 +68,12 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba params.dbuser = apikey.databaseRole; params.dbpassword = apikey.databasePassword; + //Remove this block when Auth fallback is not used anymore + // AUTH_FALLBACK + if (!params.dbpassword && global.environment.postgres.password) { + params.dbpassword = global.environment.postgres.password; + } + return callback(); }); } else { diff --git a/test/acceptance/auth/authorization-fallback.js b/test/acceptance/auth/authorization-fallback.js new file mode 100644 index 00000000..032a8d08 --- /dev/null +++ b/test/acceptance/auth/authorization-fallback.js @@ -0,0 +1,159 @@ +//Remove this file when Auth fallback is not used anymore +// AUTH_FALLBACK + +const assert = require('../../support/assert'); +const testHelper = require('../../support/test_helper'); +const CartodbWindshaft = require('../../../lib/cartodb/server'); +const serverOptions = require('../../../lib/cartodb/server_options'); +const server = new CartodbWindshaft(serverOptions); +var LayergroupToken = require('../../../lib/cartodb/models/layergroup-token'); + +function singleLayergroupConfig(sql, cartocss) { + return { + version: '1.7.0', + layers: [ + { + type: 'mapnik', + options: { + sql: sql, + cartocss: cartocss, + cartocss_version: '2.3.0' + } + } + ] + }; +} + +function createRequest(layergroup, userHost, apiKey) { + var url = layergroupUrl; + if (apiKey) { + url += '?api_key=' + apiKey; + } + return { + url: url, + method: 'POST', + headers: { + host: userHost || 'localhost', + 'Content-Type': 'application/json' + }, + data: JSON.stringify(layergroup) + }; +} + +var layergroupUrl = '/api/v1/map'; +var pointSqlMaster = "select * from test_table_private_1"; +var pointSqlPublic = "select * from test_table"; +var keysToDelete; + +describe('authorization fallback', function () { + beforeEach(function () { + keysToDelete = {}; + }); + + afterEach(function (done) { + testHelper.deleteRedisKeys(keysToDelete, done); + }); + + it("succeed with master", function (done) { + var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }'); + + assert.response(server, + createRequest(layergroup, 'user_previous_to_project_auth', '4444'), + { + status: 200 + }, + function (res, err) { + assert.ifError(err); + + var parsed = JSON.parse(res.body); + assert.ok(parsed.layergroupid); + assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + keysToDelete['user:user_previous_to_project_auth:mapviews:global'] = 5; + + done(); + } + ); + }); + + + it("succeed with default - sending default_public", function (done) { + var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }'); + + assert.response(server, + createRequest(layergroup, 'user_previous_to_project_auth', 'default_public'), + { + status: 200 + }, + function (res, err) { + assert.ifError(err); + + var parsed = JSON.parse(res.body); + assert.ok(parsed.layergroupid); + assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + keysToDelete['user:user_previous_to_project_auth:mapviews:global'] = 5; + + done(); + } + ); + }); + + + it("succeed with default - sending no api key token", function (done) { + var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }'); + + assert.response(server, + createRequest(layergroup, 'user_previous_to_project_auth'), + { + status: 200 + }, + function (res, err) { + assert.ifError(err); + + var parsed = JSON.parse(res.body); + assert.ok(parsed.layergroupid); + assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + keysToDelete['user:user_previous_to_project_auth:mapviews:global'] = 5; + + done(); + } + ); + }); + + it("fail with non-existent api key", function (done) { + var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }'); + + assert.response(server, + createRequest(layergroup, 'user_previous_to_project_auth', 'THIS-API-KEY-DOESNT-EXIST'), + { + status: 401 + }, + function (res, err) { + assert.ifError(err); + + done(); + } + ); + }); + + it("fail with default", function (done) { + var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }'); + + assert.response(server, + createRequest(layergroup, 'user_previous_to_project_auth', 'default_public'), + { + status: 403 + }, + function (res, err) { + assert.ifError(err); + + done(); + } + ); + }); +}); \ No newline at end of file diff --git a/test/support/prepare_db.sh b/test/support/prepare_db.sh index 56fcc3c9..59405389 100755 --- a/test/support/prepare_db.sh +++ b/test/support/prepare_db.sh @@ -131,6 +131,19 @@ HMSET rails:users:cartodb250user id ${TESTUSERID} \ map_key 4321 EOF + +# Remove this block when Auth fallback is not used anymore +# AUTH_FALLBACK + # A user to test auth fallback to no api keys mode + cat < Date: Fri, 16 Feb 2018 11:20:04 +0100 Subject: [PATCH 2/7] in fallback mode, use default api key if api key token doesnt exist --- lib/cartodb/api/auth_api.js | 2 ++ lib/cartodb/backends/pg_connection.js | 9 +++++- .../acceptance/auth/authorization-fallback.js | 32 ++++++++++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/cartodb/api/auth_api.js b/lib/cartodb/api/auth_api.js index 1ac2a1cc..0b93e308 100644 --- a/lib/cartodb/api/auth_api.js +++ b/lib/cartodb/api/auth_api.js @@ -88,6 +88,8 @@ AuthApi.prototype.authorizedByAPIKey = function(user, req, callback) { } if ( !isValidApiKey(apikey)) { + return callback(null, true); // AUTH_FALLBACK :S If api key not found, use default_public + const error = new Error('Unauthorized'); error.type = 'auth'; error.subtype = 'api-key-not-found'; diff --git a/lib/cartodb/backends/pg_connection.js b/lib/cartodb/backends/pg_connection.js index d5d3ecdb..c3eff05b 100644 --- a/lib/cartodb/backends/pg_connection.js +++ b/lib/cartodb/backends/pg_connection.js @@ -36,7 +36,7 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba return callback(); }); - } else if (apikeyType === 'regular') { + } else if (apikeyType === 'regular') { //Actually it can be any type of api key this.metadataBackend.getApikey(username, params.api_key || params.map_key, (err, apikey) => { if (err) { return callback(err); @@ -57,6 +57,13 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba params.dbpassword = global.environment.postgres.password; } + //Remove this block when Auth fallback is not used anymore + // AUTH_FALLBACK + // If api key not found use default + if (!params.dbuser && !params.dbpassword) { + return this.setDBAuth(username, params, 'default', callback); + } + return callback(); }); } else if (apikeyType === 'default') { diff --git a/test/acceptance/auth/authorization-fallback.js b/test/acceptance/auth/authorization-fallback.js index 032a8d08..8546c8ff 100644 --- a/test/acceptance/auth/authorization-fallback.js +++ b/test/acceptance/auth/authorization-fallback.js @@ -101,7 +101,6 @@ describe('authorization fallback', function () { ); }); - it("succeed with default - sending no api key token", function (done) { var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }'); @@ -125,17 +124,24 @@ describe('authorization fallback', function () { ); }); - it("fail with non-existent api key", function (done) { - var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }'); + it("succeed with non-existent api key - defaults to default", function (done) { + var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }'); assert.response(server, createRequest(layergroup, 'user_previous_to_project_auth', 'THIS-API-KEY-DOESNT-EXIST'), { - status: 401 + status: 200 }, function (res, err) { assert.ifError(err); + var parsed = JSON.parse(res.body); + assert.ok(parsed.layergroupid); + assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid); + + keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0; + keysToDelete['user:user_previous_to_project_auth:mapviews:global'] = 5; + done(); } ); @@ -156,4 +162,20 @@ describe('authorization fallback', function () { } ); }); -}); \ No newline at end of file + + it("fail with non-existent api key - defaults to default", function (done) { + var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }'); + + assert.response(server, + createRequest(layergroup, 'user_previous_to_project_auth', 'THIS-API-KEY-DOESNT-EXIST'), + { + status: 403 + }, + function (res, err) { + assert.ifError(err); + + done(); + } + ); + }); +}); From 5823859b2abed3d398735b3f65bda7cb186e2d23 Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Fri, 16 Feb 2018 12:00:05 +0100 Subject: [PATCH 3/7] update package.json to use the same branch form carto redis --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b2dc6652..5256f4d7 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "camshaft": "0.61.2", "cartodb-psql": "0.10.2", "cartodb-query-tables": "0.3.0", - "cartodb-redis": "cartodb/node-cartodb-redis#project-auth-api", + "cartodb-redis": "cartodb/node-cartodb-redis#project-auth-api-fallback", "debug": "^3.1.0", "dot": "~1.0.2", "express": "~4.16.0", From 7e14247ea959a089e54b5a068811db21eaf5a54c Mon Sep 17 00:00:00 2001 From: Eneko Lakasta Date: Mon, 19 Feb 2018 17:06:59 +0100 Subject: [PATCH 4/7] remove cause of unreachable code/dead code. Not necessary because carto redis assures at least the default api key --- lib/cartodb/api/auth_api.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/cartodb/api/auth_api.js b/lib/cartodb/api/auth_api.js index 677ccc86..43f19d4e 100644 --- a/lib/cartodb/api/auth_api.js +++ b/lib/cartodb/api/auth_api.js @@ -86,8 +86,6 @@ AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { } if ( !isValidApiKey(apikey)) { - return callback(null, true); // AUTH_FALLBACK :S If api key not found, use default_public - const error = new Error('Unauthorized'); error.type = 'auth'; error.subtype = 'api-key-not-found'; From 47ccb7ded8a359d66b9bb618b30651c8b7364f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Aubert?= Date: Mon, 19 Feb 2018 17:57:46 +0100 Subject: [PATCH 5/7] Point to main development branch of cartodb-redis --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5256f4d7..b2dc6652 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "camshaft": "0.61.2", "cartodb-psql": "0.10.2", "cartodb-query-tables": "0.3.0", - "cartodb-redis": "cartodb/node-cartodb-redis#project-auth-api-fallback", + "cartodb-redis": "cartodb/node-cartodb-redis#project-auth-api", "debug": "^3.1.0", "dot": "~1.0.2", "express": "~4.16.0", diff --git a/yarn.lock b/yarn.lock index c556c94e..6ce5a4b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -303,7 +303,7 @@ cartodb-query-tables@0.3.0: cartodb-redis@cartodb/node-cartodb-redis#project-auth-api: version "0.15.1" - resolved "https://codeload.github.com/cartodb/node-cartodb-redis/tar.gz/2d17fe82d66972edce5c727c679a335845ea5eb0" + resolved "https://codeload.github.com/cartodb/node-cartodb-redis/tar.gz/ffc1dccaa5ad433a1582d8e3d5926063bd3851d3" dependencies: dot "~1.0.2" redis-mpool "^0.5.0" From 2e3abfb2cd1608fb480a5460be881dd0fd31251b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Aubert?= Date: Mon, 19 Feb 2018 18:28:58 +0100 Subject: [PATCH 6/7] Catch "name not found" errors from metadata backend and set http code status 404 --- lib/cartodb/api/auth_api.js | 20 ++++++++++++-------- lib/cartodb/backends/pg_connection.js | 11 ++++++++++- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/cartodb/api/auth_api.js b/lib/cartodb/api/auth_api.js index 43f19d4e..bacccda7 100644 --- a/lib/cartodb/api/auth_api.js +++ b/lib/cartodb/api/auth_api.js @@ -70,6 +70,10 @@ AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { this.metadataBackend.getApikey(user, apikeyToken, (err, apikey) => { if (err) { + if (err.message && -1 !== err.message.indexOf('name not found')) { + err.http_status = 404; + } + return callback(err); } @@ -100,7 +104,7 @@ AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { error.subtype = 'api-key-username-mismatch'; error.http_status = 403; - return callback(error); + return callback(error); } if (!apikey.grantsMaps) { @@ -137,8 +141,8 @@ AuthApi.prototype.authorize = function(req, res, callback) { if (err) { return callback(err); - } - + } + callback(null, true); }); } @@ -147,17 +151,17 @@ AuthApi.prototype.authorize = function(req, res, callback) { if (err) { return callback(err); } - + if (isAuthorizedBySigner) { return this.pgConnection.setDBAuth(user, res.locals, 'master', function (err) { req.profiler.done('setDBAuth'); - + if (err) { return callback(err); - } + } callback(null, true); - }); + }); } // if no signer name was given, use default api key @@ -170,7 +174,7 @@ AuthApi.prototype.authorize = function(req, res, callback) { } callback(null, true); - }); + }); } // if signer name was given, return no authorization diff --git a/lib/cartodb/backends/pg_connection.js b/lib/cartodb/backends/pg_connection.js index e4f9700e..71ec2928 100644 --- a/lib/cartodb/backends/pg_connection.js +++ b/lib/cartodb/backends/pg_connection.js @@ -22,6 +22,9 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba if (apikeyType === 'master') { this.metadataBackend.getMasterApikey(username, (err, apikey) => { if (err) { + if (err.message && -1 !== err.message.indexOf('name not found')) { + err.http_status = 404; + } return callback(err); } @@ -39,6 +42,9 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba } else if (apikeyType === 'regular') { //Actually it can be any type of api key this.metadataBackend.getApikey(username, params.api_key, (err, apikey) => { if (err) { + if (err.message && -1 !== err.message.indexOf('name not found')) { + err.http_status = 404; + } return callback(err); } @@ -64,11 +70,14 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba return this.setDBAuth(username, params, 'default', callback); } - return callback(); + return callback(); }); } else if (apikeyType === 'default') { this.metadataBackend.getApikey(username, 'default_public', (err, apikey) => { if (err) { + if (err.message && -1 !== err.message.indexOf('name not found')) { + err.http_status = 404; + } return callback(err); } From 603ef4044c10ce1c6b46dac54f620638ee528cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Aubert?= Date: Mon, 19 Feb 2018 18:48:02 +0100 Subject: [PATCH 7/7] Reduce cyclomatic complexity --- lib/cartodb/api/auth_api.js | 55 +++++++++++++++++++++------ lib/cartodb/backends/pg_connection.js | 11 ++++-- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/lib/cartodb/api/auth_api.js b/lib/cartodb/api/auth_api.js index bacccda7..8782f907 100644 --- a/lib/cartodb/api/auth_api.js +++ b/lib/cartodb/api/auth_api.js @@ -70,7 +70,7 @@ AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { this.metadataBackend.getApikey(user, apikeyToken, (err, apikey) => { if (err) { - if (err.message && -1 !== err.message.indexOf('name not found')) { + if (isNameNotFoundError(err)) { err.http_status = 404; } @@ -79,15 +79,8 @@ AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { //Remove this block when Auth fallback is not used anymore // AUTH_FALLBACK - if (!apikey.databaseRole && apikey.user_id && global.environment.postgres_auth_user) { - apikey.databaseRole = _.template(global.environment.postgres_auth_user, apikey); - } - - //Remove this block when Auth fallback is not used anymore - // AUTH_FALLBACK - if (!apikey.databasePassword && global.environment.postgres.password) { - apikey.databasePassword = global.environment.postgres.password; - } + apikey.databaseRole = composeUserDatabase(apikey); + apikey.databasePassword = composeDatabasePassword(apikey); if ( !isValidApiKey(apikey)) { const error = new Error('Unauthorized'); @@ -98,7 +91,7 @@ AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { return callback(error); } - if (apikeyUsername && (apikeyUsername !== res.locals.user)) { + if (!usernameMatches(apikeyUsername, res.locals.user)) { const error = new Error('Forbidden'); error.type = 'auth'; error.subtype = 'api-key-username-mismatch'; @@ -120,6 +113,46 @@ AuthApi.prototype.authorizedByAPIKey = function(user, res, callback) { }); }; +//Remove this block when Auth fallback is not used anymore +// AUTH_FALLBACK +function composeUserDatabase (apikey) { + if (shouldComposeUserDatabase(apikey)) { + return _.template(global.environment.postgres_auth_user, apikey); + } + + return apikey.databaseRole; +} + +//Remove this block when Auth fallback is not used anymore +// AUTH_FALLBACK +function composeDatabasePassword (apikey) { + if (shouldComposeDatabasePassword(apikey)) { + return global.environment.postgres.password; + } + + return apikey.databasePassword; +} + +//Remove this block when Auth fallback is not used anymore +// AUTH_FALLBACK +function shouldComposeDatabasePassword (apikey) { + return !apikey.databasePassword && global.environment.postgres.password; +} + +//Remove this block when Auth fallback is not used anymore +// AUTH_FALLBACK +function shouldComposeUserDatabase(apikey) { + return !apikey.databaseRole && apikey.user_id && global.environment.postgres_auth_user; +} + +function isNameNotFoundError (err) { + return err.message && -1 !== err.message.indexOf('name not found'); +} + +function usernameMatches (apikeyUsername, requestUsername) { + return !(apikeyUsername && (apikeyUsername !== requestUsername)); +} + /** * Check access authorization * diff --git a/lib/cartodb/backends/pg_connection.js b/lib/cartodb/backends/pg_connection.js index 71ec2928..290fb6ef 100644 --- a/lib/cartodb/backends/pg_connection.js +++ b/lib/cartodb/backends/pg_connection.js @@ -22,7 +22,7 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba if (apikeyType === 'master') { this.metadataBackend.getMasterApikey(username, (err, apikey) => { if (err) { - if (err.message && -1 !== err.message.indexOf('name not found')) { + if (isNameNotFoundError(err)) { err.http_status = 404; } return callback(err); @@ -42,7 +42,7 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba } else if (apikeyType === 'regular') { //Actually it can be any type of api key this.metadataBackend.getApikey(username, params.api_key, (err, apikey) => { if (err) { - if (err.message && -1 !== err.message.indexOf('name not found')) { + if (isNameNotFoundError(err)) { err.http_status = 404; } return callback(err); @@ -75,7 +75,7 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba } else if (apikeyType === 'default') { this.metadataBackend.getApikey(username, 'default_public', (err, apikey) => { if (err) { - if (err.message && -1 !== err.message.indexOf('name not found')) { + if (isNameNotFoundError(err)) { err.http_status = 404; } return callback(err); @@ -97,6 +97,11 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba } }; +function isNameNotFoundError (err) { + return err.message && -1 !== err.message.indexOf('name not found'); +} + + // Set db connection parameters to those for the given username // // @param dbowner cartodb username of database owner,