API authentification (tbc...)
This commit is contained in:
+31
-5
@@ -1,5 +1,11 @@
|
||||
module.exports = function(grunt) {
|
||||
|
||||
var DEV_SERVER_PORT = 8383;
|
||||
var TEST_SERVER_PORT = 8387;
|
||||
|
||||
// Tell our Express server that Grunt launched it
|
||||
process.env.GRUNTED = true;
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
@@ -77,7 +83,7 @@ module.exports = function(grunt) {
|
||||
options: {
|
||||
reporter: 'spec',
|
||||
},
|
||||
src: ['coverage/test/server/runsDatastoreTest.js']
|
||||
src: ['coverage/test/api/apiTest.js']
|
||||
},
|
||||
coverage: {
|
||||
options: {
|
||||
@@ -85,11 +91,25 @@ module.exports = function(grunt) {
|
||||
quiet: true,
|
||||
captureFile: 'coverage/coverage.html'
|
||||
},
|
||||
src: ['coverage/test/api/*.js']
|
||||
src: ['coverage/test/core/*.js', 'coverage/test/api/*.js']
|
||||
}
|
||||
},
|
||||
express: {
|
||||
test: {
|
||||
dev: {
|
||||
options: {
|
||||
port: 8383,
|
||||
server: './bin/server.js',
|
||||
serverreload: true,
|
||||
showStack: true
|
||||
}
|
||||
},
|
||||
testServer: {
|
||||
options: {
|
||||
port: 8387,
|
||||
server: './bin/server.js'
|
||||
}
|
||||
},
|
||||
testSuite: {
|
||||
options: {
|
||||
port: 8388,
|
||||
bases: 'test/www'
|
||||
@@ -114,10 +134,15 @@ module.exports = function(grunt) {
|
||||
'jshint'
|
||||
]);
|
||||
|
||||
grunt.registerTask('dev', [
|
||||
'express:dev'
|
||||
]);
|
||||
|
||||
grunt.registerTask('test', [
|
||||
'build',
|
||||
'jshint',
|
||||
'express:test',
|
||||
'express:testServer',
|
||||
'express:testSuite',
|
||||
'clean:coverage',
|
||||
'blanket',
|
||||
'copy:coverage',
|
||||
@@ -128,7 +153,8 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('test-current-work', [
|
||||
'build',
|
||||
'jshint',
|
||||
'express:test',
|
||||
'express:testServer',
|
||||
'express:testSuite',
|
||||
'clean:coverage',
|
||||
'blanket',
|
||||
'copy:coverage',
|
||||
|
||||
+13
-4
@@ -7,8 +7,11 @@ var server = require('http').createServer(app);
|
||||
var bodyParser = require('body-parser');
|
||||
var compress = require('compression');
|
||||
|
||||
var authMiddleware = require('../lib/server/authMiddleware');
|
||||
|
||||
app.use(compress());
|
||||
app.use(bodyParser.json());
|
||||
app.use(authMiddleware);
|
||||
|
||||
|
||||
// Initialize the controllers
|
||||
@@ -16,7 +19,13 @@ var apiController = require('../lib/server/controllers/apiController')
|
||||
var uiController = require('../lib/server/controllers/uiController')(app);
|
||||
|
||||
|
||||
// Launch the server
|
||||
server.listen(settings.serverPort, function() {
|
||||
console.log('Listening on port %d', server.address().port);
|
||||
});
|
||||
// Let's start the server!
|
||||
if (!process.env.GRUNTED) {
|
||||
// The server is not launched by Grunt
|
||||
server.listen(settings.serverPort, function() {
|
||||
console.log('Listening on port %d', server.address().port);
|
||||
});
|
||||
}
|
||||
|
||||
// For Grunt
|
||||
module.exports = app;
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "yellowlabtools",
|
||||
"dependencies": {
|
||||
"angular": "~1.3.1",
|
||||
"angular": "~1.3.5",
|
||||
"ngModal": "git://github.com/gmetais/ngModal.git#1.2.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
var config = require('../../server_config/settings.json');
|
||||
|
||||
var jwt = require('jwt-simple');
|
||||
var debug = require('debug')('authMiddleware');
|
||||
|
||||
|
||||
var authMiddleware = function(req, res, next) {
|
||||
'use strict';
|
||||
|
||||
if (req.path.indexOf('/api/') === 0) {
|
||||
|
||||
// Test if it's an authorized key
|
||||
if (req.headers && req.headers['x-api-key'] && isApiKeyValid(req.headers['x-api-key'])) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
// Test if it's an authorized token
|
||||
if (req.headers && req.headers['x-api-token'] && isTokenValid(req.headers['x-api-token'])) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(401).send('Unauthorized');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function isApiKeyValid(apiKey) {
|
||||
return (config.authorizedKeys[apiKey]) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
function isTokenValid(token) {
|
||||
|
||||
var data = null;
|
||||
|
||||
try {
|
||||
jwt.decode(token, config.tokenSalt);
|
||||
} catch(err) {
|
||||
debug('Error while decoding token');
|
||||
debug(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return data.expire &&
|
||||
data.expire > Date.now() &&
|
||||
data.application &&
|
||||
config.authorizedApplications.indexOf(data.application) >= 0;
|
||||
}
|
||||
|
||||
module.exports = authMiddleware;
|
||||
@@ -13,10 +13,7 @@ var ApiController = function(app) {
|
||||
var runsDatastore = new RunsDatastore();
|
||||
var resultsDatastore = new ResultsDatastore();
|
||||
|
||||
// Retrieve the list of all runs
|
||||
/*app.get('/api/runs', function(req, res) {
|
||||
// NOT YET
|
||||
});*/
|
||||
|
||||
|
||||
// Create a new run
|
||||
app.post('/api/runs', function(req, res) {
|
||||
@@ -107,6 +104,11 @@ var ApiController = function(app) {
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieve the list of all runs
|
||||
/*app.get('/api/runs', function(req, res) {
|
||||
// NOT YET
|
||||
});*/
|
||||
|
||||
// Delete one run by id
|
||||
/*app.delete('/api/runs/:id', function(req, res) {
|
||||
deleteRun()
|
||||
@@ -125,7 +127,7 @@ var ApiController = function(app) {
|
||||
// Exists
|
||||
app.head('/api/runs/:id', function(req, res) {
|
||||
existsX();
|
||||
// Retourne 200 si existe ou 404 si n'existe pas
|
||||
// Returns 200 if the result exists or 404 if not
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
+7
-5
@@ -11,16 +11,17 @@
|
||||
"main": "./lib/yellowlabtools.js",
|
||||
"dependencies": {
|
||||
"async": "~0.9.0",
|
||||
"body-parser": "~1.9.2",
|
||||
"compression": "~1.2.0",
|
||||
"body-parser": "~1.10.0",
|
||||
"compression": "~1.2.1",
|
||||
"debug": "^2.1.0",
|
||||
"express": "~4.10.4",
|
||||
"jwt-simple": "^0.2.0",
|
||||
"phantomas": "1.7.0",
|
||||
"rimraf": "^2.2.8",
|
||||
"socket.io": "~1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^1.9.2",
|
||||
"chai": "^1.10.0",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-blanket": "^0.0.8",
|
||||
"grunt-contrib-clean": "^0.6.0",
|
||||
@@ -29,11 +30,12 @@
|
||||
"grunt-contrib-less": "^0.12.0",
|
||||
"grunt-express": "^1.4.1",
|
||||
"grunt-fontsmith": "^0.9.1",
|
||||
"grunt-mocha-test": "^0.12.2",
|
||||
"grunt-mocha-test": "^0.12.4",
|
||||
"matchdep": "^0.3.0",
|
||||
"mocha": "^2.0.1",
|
||||
"phantomjs": "^1.9.10",
|
||||
"phantomjs": "^1.9.12",
|
||||
"q": "^1.1.2",
|
||||
"request": "^2.49.0",
|
||||
"sinon": "^1.12.1",
|
||||
"sinon-chai": "^2.6.0"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
{
|
||||
"serverPort": 80,
|
||||
"googleAnalyticsId": "UA-54493828-1"
|
||||
"googleAnalyticsId": "UA-54493828-1",
|
||||
|
||||
"authorized-keys": {
|
||||
|
||||
},
|
||||
"tokenSalt": "",
|
||||
"authorizedApplications": [
|
||||
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,12 @@
|
||||
{
|
||||
"serverPort": 8383,
|
||||
"googleAnalyticsId": ""
|
||||
"googleAnalyticsId": "",
|
||||
|
||||
"authorizedKeys": {
|
||||
"1234567890": "contact@gaelmetais.com"
|
||||
},
|
||||
"tokenSalt": "lake-city",
|
||||
"authorizedApplications": [
|
||||
"frontend"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
var should = require('chai').should();
|
||||
var request = require('request');
|
||||
var jwt = require('jwt-simple');
|
||||
|
||||
var config = {
|
||||
"authorizedKeys": {
|
||||
"1234567890": "test@test.com"
|
||||
},
|
||||
"tokenSalt": "test-salt",
|
||||
"authorizedApplications": ["wooot"]
|
||||
};
|
||||
|
||||
var apiUrl = 'http://localhost:8387/api';
|
||||
var wwwUrl = 'http://localhost:8388';
|
||||
|
||||
describe('api', function() {
|
||||
|
||||
var runId;
|
||||
|
||||
it('should not accept a query if there is no key in headers', function(done) {
|
||||
this.timeout(5000);
|
||||
|
||||
request({
|
||||
method: 'POST',
|
||||
url: apiUrl + '/runs',
|
||||
body: {
|
||||
url: wwwUrl + '/simple-page.html',
|
||||
waitForResponse: false
|
||||
},
|
||||
json: true
|
||||
}, function(error, response, body) {
|
||||
if (!error && response.statusCode === 401) {
|
||||
done();
|
||||
} else {
|
||||
done(error || response.statusCode);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should refuse a query with an invalid key', function(done) {
|
||||
this.timeout(5000);
|
||||
|
||||
request({
|
||||
method: 'POST',
|
||||
url: apiUrl + '/runs',
|
||||
body: {
|
||||
url: wwwUrl + '/simple-page.html',
|
||||
waitForResponse: false
|
||||
},
|
||||
json: true,
|
||||
headers: {
|
||||
'X-Api-Key': 'invalid'
|
||||
}
|
||||
}, function(error, response, body) {
|
||||
if (!error && response.statusCode === 401) {
|
||||
done();
|
||||
} else {
|
||||
done(error || response.statusCode);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept a query with a valid key', function(done) {
|
||||
this.timeout(5000);
|
||||
|
||||
request({
|
||||
method: 'POST',
|
||||
url: apiUrl + '/runs',
|
||||
body: {
|
||||
url: wwwUrl + '/simple-page.html',
|
||||
waitForResponse: false
|
||||
},
|
||||
json: true,
|
||||
headers: {
|
||||
'X-Api-Key': Object.keys(config.authorizedKeys)[0]
|
||||
}
|
||||
}, function(error, response, body) {
|
||||
if (!error && response.statusCode === 200) {
|
||||
|
||||
runId = body.runId;
|
||||
runId.should.be.a('string');
|
||||
done();
|
||||
|
||||
} else {
|
||||
done(error || response.statusCode);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should refuse an expired token', function(done) {
|
||||
this.timeout(5000);
|
||||
|
||||
request({
|
||||
method: 'POST',
|
||||
url: apiUrl + '/runs',
|
||||
body: {
|
||||
url: wwwUrl + '/simple-page.html',
|
||||
waitForResponse: false
|
||||
},
|
||||
json: true,
|
||||
headers: {
|
||||
'X-Api-Token': jwt.encode({
|
||||
application: config.authorizedApplications[0],
|
||||
expire: Date.now() - 60000
|
||||
}, config.tokenSalt)
|
||||
}
|
||||
}, function(error, response, body) {
|
||||
if (!error && response.statusCode === 401) {
|
||||
done();
|
||||
} else {
|
||||
done(error || response.statusCode);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should refuse a token from an unknown app', function(done) {
|
||||
this.timeout(5000);
|
||||
|
||||
request({
|
||||
method: 'POST',
|
||||
url: apiUrl + '/runs',
|
||||
body: {
|
||||
url: wwwUrl + '/simple-page.html',
|
||||
waitForResponse: false
|
||||
},
|
||||
json: true,
|
||||
headers: {
|
||||
'X-Api-Token': jwt.encode({
|
||||
application: 'unknown-app',
|
||||
expire: Date.now() + 60000
|
||||
}, config.tokenSalt)
|
||||
}
|
||||
}, function(error, response, body) {
|
||||
if (!error && response.statusCode === 401) {
|
||||
done();
|
||||
} else {
|
||||
done(error || response.statusCode);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept a good token', function(done) {
|
||||
this.timeout(5000);
|
||||
|
||||
request({
|
||||
method: 'POST',
|
||||
url: apiUrl + '/runs',
|
||||
body: {
|
||||
url: wwwUrl + '/simple-page.html',
|
||||
waitForResponse: false
|
||||
},
|
||||
json: true,
|
||||
headers: {
|
||||
'X-Api-Token': jwt.encode({
|
||||
application: config.authorizedApplications[0],
|
||||
expire: Date.now() + 60000
|
||||
}, config.tokenSalt)
|
||||
}
|
||||
}, function(error, response, body) {
|
||||
if (!error && response.statusCode === 200) {
|
||||
|
||||
runId = body.runId;
|
||||
runId.should.be.a('string');
|
||||
done();
|
||||
|
||||
} else {
|
||||
done(error || response.statusCode);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user