get and check api key credentials from api key: username and token

This commit is contained in:
Eneko Lakasta 2018-02-15 17:49:47 +01:00
parent 11aa4d12bd
commit cda2616a8a
8 changed files with 127 additions and 81 deletions

View File

@ -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';

View File

@ -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(),
];
/**

View File

@ -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();
};

View File

@ -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();
};

View File

@ -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)
];

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}