2018-10-24 00:39:02 +08:00
|
|
|
'use strict';
|
|
|
|
|
2019-10-07 16:44:45 +08:00
|
|
|
var test_helper = require('../support/test-helper');
|
2015-04-28 01:15:06 +08:00
|
|
|
var RedisPool = require('redis-mpool');
|
|
|
|
var querystring = require('querystring');
|
|
|
|
|
|
|
|
var assert = require('../support/assert');
|
2015-09-23 01:48:08 +08:00
|
|
|
var mapnik = require('windshaft').mapnik;
|
2019-10-07 16:55:26 +08:00
|
|
|
var CartodbWindshaft = require('../../lib/server');
|
|
|
|
var serverOptions = require('../../lib/server-options');
|
2019-10-07 16:50:14 +08:00
|
|
|
var TemplateMaps = require('../../lib/backends/template-maps');
|
2019-10-07 15:51:51 +08:00
|
|
|
var NamedMapsCacheEntry = require('../../lib/cache/model/named-maps-entry');
|
2015-04-28 01:15:06 +08:00
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
describe('named maps authentication', function () {
|
2018-04-16 22:16:23 +08:00
|
|
|
var server;
|
|
|
|
|
|
|
|
before(function () {
|
|
|
|
server = new CartodbWindshaft(serverOptions);
|
|
|
|
});
|
2018-04-16 20:09:24 +08:00
|
|
|
|
2015-04-28 01:15:06 +08:00
|
|
|
// configure redis pool instance to use in tests
|
|
|
|
var redisPool = new RedisPool(global.environment.redis);
|
|
|
|
|
|
|
|
var templateMaps = new TemplateMaps(redisPool, {
|
|
|
|
max_user_templates: global.environment.maxUserTemplates
|
|
|
|
});
|
|
|
|
|
|
|
|
var wadusLayer = {
|
|
|
|
type: 'cartodb',
|
|
|
|
options: {
|
|
|
|
sql: 'select 1 cartodb_id, null::geometry the_geom_webmercator',
|
|
|
|
cartocss: '#layer { marker-fill: <%= color %>; }',
|
|
|
|
cartocss_version: '2.3.0'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var username = 'localhost';
|
|
|
|
|
|
|
|
var templateName = 'valid_template';
|
|
|
|
var template = {
|
|
|
|
version: '0.0.1',
|
|
|
|
name: templateName,
|
|
|
|
auth: {
|
|
|
|
method: 'open'
|
|
|
|
},
|
2019-10-22 01:07:24 +08:00
|
|
|
placeholders: {
|
|
|
|
color: {
|
|
|
|
type: 'css_color',
|
|
|
|
default: '#cc3300'
|
2015-04-28 01:15:06 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
layergroup: {
|
|
|
|
layers: [
|
|
|
|
wadusLayer
|
|
|
|
]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var tokenAuthTemplateName = 'auth_valid_template';
|
|
|
|
var tokenAuthTemplate = {
|
|
|
|
version: '0.0.1',
|
|
|
|
name: tokenAuthTemplateName,
|
|
|
|
auth: {
|
|
|
|
method: 'token',
|
|
|
|
valid_tokens: ['valid1', 'valid2']
|
|
|
|
},
|
|
|
|
placeholders: {
|
|
|
|
color: {
|
2019-10-22 01:07:24 +08:00
|
|
|
type: 'css_color',
|
|
|
|
default: '#cc3300'
|
2015-04-28 01:15:06 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
layergroup: {
|
|
|
|
layers: [
|
|
|
|
wadusLayer
|
|
|
|
]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var namedMapLayer = {
|
|
|
|
type: 'named',
|
|
|
|
options: {
|
|
|
|
name: templateName,
|
|
|
|
config: {},
|
|
|
|
auth_tokens: []
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var nestedNamedMapTemplateName = 'nested_template';
|
|
|
|
var nestedNamedMapTemplate = {
|
|
|
|
version: '0.0.1',
|
|
|
|
name: nestedNamedMapTemplateName,
|
|
|
|
auth: {
|
|
|
|
method: 'open'
|
|
|
|
},
|
|
|
|
layergroup: {
|
|
|
|
layers: [
|
|
|
|
namedMapLayer
|
|
|
|
]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-09-25 20:23:13 +08:00
|
|
|
beforeEach(function (done) {
|
2015-04-28 01:15:06 +08:00
|
|
|
templateMaps.addTemplate(username, nestedNamedMapTemplate, function (err) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
templateMaps.addTemplate(username, tokenAuthTemplate, function (err) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
templateMaps.addTemplate(username, template, function (err) {
|
|
|
|
return done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-25 20:23:13 +08:00
|
|
|
afterEach(function (done) {
|
2015-04-28 01:15:06 +08:00
|
|
|
templateMaps.delTemplate(username, nestedNamedMapTemplateName, function (err) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
templateMaps.delTemplate(username, tokenAuthTemplateName, function (err) {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
templateMaps.delTemplate(username, templateName, function (err) {
|
|
|
|
return done(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
function getNamedTile (name, z, x, y, options, callback) {
|
|
|
|
var url = '/api/v1/map/named/' + name + '/all/' + [z, x, y].join('/') + '.png';
|
2015-09-23 01:48:08 +08:00
|
|
|
if (options.params) {
|
|
|
|
url = url + '?' + querystring.stringify(options.params);
|
|
|
|
}
|
|
|
|
var requestOptions = {
|
|
|
|
url: url,
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
|
|
|
host: username
|
|
|
|
},
|
|
|
|
encoding: 'binary'
|
|
|
|
};
|
|
|
|
|
|
|
|
var statusCode = options.status || 200;
|
|
|
|
|
|
|
|
var expectedResponse = {
|
|
|
|
status: statusCode,
|
|
|
|
headers: {
|
|
|
|
'Content-Type': statusCode === 200 ? 'image/png' : 'application/json; charset=utf-8'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
assert.response(server,
|
|
|
|
requestOptions,
|
|
|
|
expectedResponse,
|
|
|
|
function (res, err) {
|
|
|
|
var img;
|
|
|
|
if (!err && res.headers['content-type'] === 'image/png') {
|
|
|
|
img = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
|
|
|
|
}
|
|
|
|
return callback(err, res, img);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
describe('tiles', function () {
|
2015-09-23 01:59:27 +08:00
|
|
|
it('should return a 404 error for nonexistent template name', function (done) {
|
|
|
|
var nonexistentName = 'nonexistent';
|
2019-10-22 01:07:24 +08:00
|
|
|
getNamedTile(nonexistentName, 0, 0, 0, { status: 404 }, function (err, res) {
|
2015-09-23 01:59:27 +08:00
|
|
|
assert.ok(!err);
|
2019-10-22 01:52:51 +08:00
|
|
|
assert.deepStrictEqual(
|
2016-06-13 22:14:01 +08:00
|
|
|
JSON.parse(res.body).errors,
|
|
|
|
["Template '" + nonexistentName + "' of user '" + username + "' not found"]
|
2015-09-23 01:59:27 +08:00
|
|
|
);
|
|
|
|
done();
|
|
|
|
});
|
2015-09-23 01:48:08 +08:00
|
|
|
});
|
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
it('should return 403 if not properly authorized', function (done) {
|
|
|
|
getNamedTile(tokenAuthTemplateName, 0, 0, 0, { status: 403 }, function (err, res) {
|
2015-09-23 01:59:27 +08:00
|
|
|
assert.ok(!err);
|
2019-10-22 01:52:51 +08:00
|
|
|
assert.deepStrictEqual(JSON.parse(res.body).errors, ['Unauthorized template instantiation']);
|
2015-09-23 01:59:27 +08:00
|
|
|
done();
|
|
|
|
});
|
2015-09-23 01:48:08 +08:00
|
|
|
});
|
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
it('should return 200 if properly authorized', function (done) {
|
|
|
|
getNamedTile(tokenAuthTemplateName, 0, 0, 0, { params: { auth_token: 'valid1' } }, function (err, res, img) {
|
2019-10-22 01:41:03 +08:00
|
|
|
assert.strictEqual(img.width(), 256);
|
|
|
|
assert.strictEqual(img.height(), 256);
|
2015-09-23 01:48:08 +08:00
|
|
|
|
2015-09-23 01:59:27 +08:00
|
|
|
assert.ok(!err);
|
|
|
|
test_helper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, tokenAuthTemplateName).key());
|
|
|
|
done();
|
|
|
|
});
|
2015-09-23 01:48:08 +08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
function getStaticMap (name, options, callback) {
|
2015-04-28 01:15:06 +08:00
|
|
|
var url = '/api/v1/map/static/named/' + name + '/640/480.png';
|
|
|
|
if (options.params) {
|
|
|
|
url = url + '?' + querystring.stringify(options.params);
|
|
|
|
}
|
|
|
|
var requestOptions = {
|
|
|
|
url: url,
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
|
|
|
host: username
|
2015-09-23 01:48:08 +08:00
|
|
|
},
|
|
|
|
encoding: 'binary'
|
2015-04-28 01:15:06 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
var statusCode = options.status || 200;
|
|
|
|
|
|
|
|
var expectedResponse = {
|
|
|
|
status: statusCode,
|
|
|
|
headers: {
|
|
|
|
'Content-Type': statusCode === 200 ? 'image/png' : 'application/json; charset=utf-8'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
assert.response(server,
|
|
|
|
requestOptions,
|
|
|
|
expectedResponse,
|
|
|
|
function (res, err) {
|
2015-09-23 01:48:08 +08:00
|
|
|
var img;
|
|
|
|
if (!err && res.headers['content-type'] === 'image/png') {
|
|
|
|
img = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
|
|
|
|
}
|
|
|
|
return callback(err, res, img);
|
2015-04-28 01:15:06 +08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
2019-10-22 01:07:24 +08:00
|
|
|
describe('static maps', function () {
|
2015-09-23 01:59:27 +08:00
|
|
|
it('should return a 404 error for nonexistent template name', function (done) {
|
|
|
|
var nonexistentName = 'nonexistent';
|
2019-10-22 01:07:24 +08:00
|
|
|
getStaticMap(nonexistentName, { status: 404 }, function (err, res) {
|
2015-09-23 01:59:27 +08:00
|
|
|
assert.ok(!err);
|
2019-10-22 01:52:51 +08:00
|
|
|
assert.deepStrictEqual(
|
2016-06-13 22:14:01 +08:00
|
|
|
JSON.parse(res.body).errors,
|
|
|
|
["Template '" + nonexistentName + "' of user '" + username + "' not found"]
|
2015-09-23 01:59:27 +08:00
|
|
|
);
|
|
|
|
done();
|
|
|
|
});
|
2015-04-28 01:15:06 +08:00
|
|
|
});
|
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
it('should return 403 if not properly authorized', function (done) {
|
|
|
|
getStaticMap(tokenAuthTemplateName, { status: 403 }, function (err, res) {
|
2015-09-23 01:59:27 +08:00
|
|
|
assert.ok(!err);
|
2019-10-22 01:52:51 +08:00
|
|
|
assert.deepStrictEqual(JSON.parse(res.body).errors, ['Unauthorized template instantiation']);
|
2015-09-23 01:59:27 +08:00
|
|
|
done();
|
|
|
|
});
|
2015-04-28 01:15:06 +08:00
|
|
|
});
|
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
it('should return 200 if properly authorized', function (done) {
|
|
|
|
getStaticMap(tokenAuthTemplateName, { params: { auth_token: 'valid1' } }, function (err, res, img) {
|
2015-09-23 01:59:27 +08:00
|
|
|
assert.ok(!err);
|
2015-09-23 01:48:08 +08:00
|
|
|
|
2019-10-22 01:41:03 +08:00
|
|
|
assert.strictEqual(img.width(), 640);
|
|
|
|
assert.strictEqual(img.height(), 480);
|
2015-09-23 01:48:08 +08:00
|
|
|
|
2015-09-23 01:59:27 +08:00
|
|
|
test_helper.checkSurrogateKey(res, new NamedMapsCacheEntry(username, tokenAuthTemplateName).key());
|
2019-10-22 01:07:24 +08:00
|
|
|
test_helper.deleteRedisKeys({ 'user:localhost:mapviews:global': 5 }, done);
|
2015-09-23 01:59:27 +08:00
|
|
|
});
|
2015-04-28 01:15:06 +08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|