Skip to content

Commit

Permalink
Make new HTTP unit tests pass
Browse files Browse the repository at this point in the history
Update the configuration description of the authentication and authorization callbacks in the README.md
  • Loading branch information
healarconr committed Oct 23, 2014
1 parent 9ac6d0f commit 4960f11
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 43 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ module.exports = {
coap: {
/**
* @param {Object} req The incoming message @link https://github.com/mcollina/node-coap#incoming
* @param {Function} callback The callback function. Has the following structure: callback(error, authenticated, [subject])
* @param {Function} callback The callback function. Has the following structure: callback(error, authenticated, subject)
*/
authenticate: function(req, callback) {
// Examples:
Expand Down Expand Up @@ -287,7 +287,7 @@ module.exports = {
http: {
/**
* @param {Object} req The request object
* @param {Function} callback The callback function. Has the following structure: callback(error, success, [subject])
* @param {Function} callback The callback function. Has the following structure: callback(error, authenticated, subject)
*/
authenticate: function(req, callback) {
// See coap.authenticate
Expand All @@ -303,7 +303,7 @@ module.exports = {
/**
* @param {Object} subject The subject returned by the authenticate function
* @param {string} topic The topic
* @param {Buffer} payload The payload
* @param {string} payload The payload
* @param {Function} callback The callback function. Has the following structure: callback(error, authorized)
*/
authorizePut: function(subject, topic, payload, callback) {
Expand Down
4 changes: 2 additions & 2 deletions lib/coap.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ CoAP.prototype._handlePUT = function(topic, payload, res) {
* This default implementation authenticates everybody.
* The returned subject is just a new Object.
*
* @param {Object} req The request object
* @param {Function} cb The callback function. Has the following structure: cb(err, authenticated, [subject])
* @param {Object} req The incoming message @link https://github.com/mcollina/node-coap#incoming
* @param {Function} cb The callback function. Has the following structure: cb(err, authenticated, subject)
*/
CoAP.prototype.authenticate = function(req, cb) {
cb(null, true, {});
Expand Down
192 changes: 154 additions & 38 deletions lib/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ function HTTP(opts, done) {
var that = this;
this._persistence = opts.ponte.persistence;
this._ponte = opts.ponte;

if (typeof opts.authenticate === "function") {
this.authenticate = opts.authenticate;
}

if (typeof opts.authorizeGet === "function") {
this.authorizeGet = opts.authorizeGet;
}

if (typeof opts.authorizePut === "function") {
this.authorizePut = opts.authorizePut;
}

var logger = this._logger = opts.ponte.logger.child({
service: 'HTTP',
serializers: {
Expand All @@ -59,6 +72,28 @@ HTTP.prototype.buildServer = function(opts) {
var logger = this._logger;
var persistence = this._persistence;
var ponte = this._ponte;

var authenticate = this.authenticate;
var authorizeGet = this.authorizeGet;
var authorizePut = this.authorizePut;

function handleAuthError(err, res) {
logger.info(err);
res.statusCode = 500;
res.end();
}

function handleNotAuthenticated(res) {
logger.info('authentication denied');
res.statusCode = 401;
res.end();
}

function handleNotAuthorized(res) {
logger.info('not authorized');
res.statusCode = 403;
res.end();
}

var handlePontePublic = st(__dirname + "/../public", {
index: false,
Expand All @@ -70,49 +105,75 @@ HTTP.prototype.buildServer = function(opts) {
passthrough: false
});

function handleGetResource(req, res) {
var match = req.url.match(resourcesRegexp);
if (req.method !== 'GET' || !match) {
function handleGetResource(subject, topic, req, res) {
if (req.method !== 'GET') {
return false;
}

var topic = match[1];

persistence.lookupRetained(topic, function(err, packets) {
if (packets.length === 0) {
res.statusCode = 404;
res.end('Not found');
} else {
res.end(packets[0].payload);

authorizeGet(subject, topic, function(err, authorized) {
if (err) {
handleAuthError(err, res);
return;
}

if (!authorized) {
handleNotAuthorized(res);
return;
}

persistence.lookupRetained(topic, function(err, packets) {
if (packets.length === 0) {
res.statusCode = 404;
res.end('Not found');
} else {
res.end(packets[0].payload);
}
});

});

return true;
}

function handlePutResource(req, res) {
var match = req.url.match(resourcesRegexp);
if (req.method !== 'PUT' && req.method !== 'POST' || !match) {
function handlePutResource(subject, topic, req, res) {
if (req.method !== 'PUT' && req.method !== 'POST') {
return false;
}

var topic = match[1];

req.pipe(callback(function(err, payload) {
payload = payload.toString();
var packet = { topic: topic, payload: payload, retain: true };
persistence.storeRetained(packet, function() {
ponte.broker.publish(topic, payload, {}, function() {
res.setHeader('Location', '/resources/' + topic);
res.statusCode = 204;
res.end();
ponte.emit('updated', topic, new Buffer(payload));

authorizePut(subject, topic, payload, function(err, authorized) {
if (err) {
handleAuthError(err, res);
return;
}

if (!authorized) {
handleNotAuthorized(res);
return;
}

var packet = { topic: topic, payload: payload, retain: true };
persistence.storeRetained(packet, function() {
ponte.broker.publish(topic, payload, {}, function() {
res.setHeader('Location', '/resources/' + topic);
res.statusCode = 204;
res.end();
ponte.emit('updated', topic, new Buffer(payload));
});
});

});
}));

return true;
}

function handleNotFound(res) {
res.writeHeader(404);
res.end("Not Found");
}

return corsify({
endOptions: true
Expand All @@ -122,24 +183,79 @@ HTTP.prototype.buildServer = function(opts) {
res.on('finish', function() {
logger.info({ res: res });
});

// Only authenticate requests to the resources
var match = req.url.match(resourcesRegexp);
if (match) {
topic = match[1];

authenticate(req, function(err, authenticated, subject) {
if (err) {
handleAuthError(err, res);
return;
}

if (!authenticated) {
handleNotAuthenticated(res);
return;
}

var handled =
handleGetResource(subject, topic, req, res) ||
handlePutResource(subject, topic, req, res);

var handled =
handleGetResource(req, res) ||
handlePutResource(req, res);

if (handled) {
return;
}

if (opts.serveLibraries) {
handlePontePublic(req, res, function() {
handleMoscaPublic(req, res);
if (!handled) {
handleNotFound(res);
}
});
} else {
res.writeHeader(404);
res.end("Not Found");
// Public libraries do not require authentication
if (opts.serveLibraries) {
handlePontePublic(req, res, function() {
handleMoscaPublic(req, res);
});
} else {
handleNotFound(res);
}
}
});
};

/**
* The function that will be used to authenticate requests.
* This default implementation authenticates everybody.
* The returned subject is just a new Object.
*
* @param {Object} req The request object
* @param {Function} cb The callback function. Has the following structure: cb(err, authenticated, subject)
*/
HTTP.prototype.authenticate = function(req, cb) {
cb(null, true, {});
};

/**
* The function that will be used to authorize subjects to GET messages from topics.
* This default implementation authorizes everybody.
*
* @param {Object} subject The subject returned by the authenticate function
* @param {string} topic The topic
* @param {Function} cb The callback function. Has the following structure: cb(err, authorized)
*/
HTTP.prototype.authorizeGet = function(subject, topic, cb) {
cb(null, true);
};

/**
* The function that will be used to authorize subjects to PUT messages to topics.
* This default implementation authorizes everybody.
*
* @param {Object} subject The subject returned by the authenticate function
* @param {string} topic The topic
* @param {string} payload The payload
* @param {Function} cb The callback function. Has the following structure: cb(err, authorized)
*/
HTTP.prototype.authorizePut = function(subject, topic, payload, cb) {
cb(null, true);
};

module.exports = HTTP;

0 comments on commit 4960f11

Please sign in to comment.