Skip to content
Browse files

playing around with http authorizations, have a working example on na…

…vajo.conf
  • Loading branch information...
1 parent 20c8ab2 commit 6ea6d51bb0ef7e9d3860513e54d094a1a4dcc30b @dresende committed
Showing with 135 additions and 0 deletions.
  1. +105 −0 core/auth.js
  2. +21 −0 core/utils.js
  3. +9 −0 navajo.conf
View
105 core/auth.js
@@ -0,0 +1,105 @@
+var authorization_nonces = {};
+
+exports.generateAuthorization = generateAuthorization;
+exports.checkAuthorization = checkAuthorization;
+
+function generateAuthorization(res, realm, mech) {
+ res.statusCode = 401;
+
+ switch (mech.toLowerCase()) {
+ case "basic":
+ res.setHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
+ break;
+ case "digest":
+ var nonce = md5("" + (new Date()).getTime() + Math.random()),
+ opaque = md5("hostname or something");
+
+ authorization_nonces[nonce] = {
+ "nc" : 1
+ };
+
+ res.setHeader("WWW-Authenticate", "Digest realm=\"" + realm + "\", " +
+ "qop=\"auth\", " +
+ "nonce=\"" + nonce + "\", " +
+ "opaque=\"" + opaque + "\"");
+ break;
+ default:
+ throw { "code": "ENOMECH", "message": "Unknown Authorization mech" };
+ }
+ return res.end();
+}
+
+function checkAuthorization(authorization, method, realm, users) {
+ var querystring = require("querystring"),
+ m = null,
+ auth = {};
+
+ if ((m = authorization.match(/^\w+\s/)) !== null) {
+ auth.mech = m[0].trimRight().toLowerCase();
+ auth.data = authorization.substr(auth.mech.length).trimLeft();
+ auth.validated = false;
+
+ switch (auth.mech) {
+ case "basic":
+ var b = (new Buffer(auth.data, "base64")).toString().split(":", 2);
+
+ auth.username = b[0];
+ auth.password = b[1];
+ auth.validated = users.hasOwnProperty(auth.username) && users[auth.username] === auth.password;
+ break;
+ case "digest":
+ auth.data = querystring.parse(auth.data, ",", "=");
+ for (k in auth.data) {
+ if (!auth.data.hasOwnProperty(k)) continue;
+
+ if (k.trimLeft() != k) {
+ auth.data[k.trimLeft()] = auth.data[k];
+ delete auth.data[k];
+ }
+ }
+ for (k in auth.data) {
+ if (!auth.data.hasOwnProperty(k)) continue;
+
+ if (auth.data[k].substr(0, 1) == "\"" && auth.data[k].substr(-1) == "\"") {
+ auth.data[k] = auth.data[k].substr(1, auth.data[k].length - 2);
+ }
+ }
+
+ auth.username = auth.data.username;
+
+ if (!users.hasOwnProperty(auth.username)) {
+ break;
+ }
+
+ if (!authorization_nonces.hasOwnProperty(auth.data.nonce)) {
+ break;
+ }
+
+ var a1 = [ auth.username, realm, users[auth.username] ].join(":"),
+ a2 = [ method, auth.data.uri ].join(":"),
+ digest = "";
+
+ if (auth.data.hasOwnProperty("qop")) {
+ if (parseInt(auth.data.nc, 10) < authorization_nonces[auth.data.nonce].nc) {
+ break;
+ }
+
+ authorization_nonces[auth.data.nonce].nc = auth.data.nc;
+ digest = md5([ md5(a1), auth.data.nonce, auth.data.nc, auth.data.cnonce, auth.data.qop, md5(a2) ].join(":"));
+ } else {
+ digest = md5([ md5(a1), auth.data.nonce, md5(a2) ].join(":"));
+ }
+
+ auth.validated = (digest === auth.data.response);
+ break;
+ }
+ }
+
+ return auth;
+}
+
+function md5(str) {
+ var hash = require("crypto").createHash("MD5");
+ hash.update(str);
+ return hash.digest("hex");
+}
View
21 core/utils.js
@@ -3,6 +3,7 @@ var path = require("path"),
parse_url = require("url").parse,
mime = require("mime"),
print = require("./print"),
+ auth = require("./auth"),
config = {
"bind" : "0.0.0.0:80",
"root" : "www/",
@@ -181,6 +182,26 @@ function replyWithIndex(base_path, files, index, url, req, res) {
function streamFile(file, url, req, res) {
var mime_type = mime.lookup(file);
+ if (config.authorizations) {
+ for (uri in config.authorizations) {
+ if (!config.authorizations.hasOwnProperty(uri)) continue;
+
+ if (url.pathname.substr(0, uri.length) == uri) {
+ // need authorization
+ var validated = false;
+
+ if (req.headers.hasOwnProperty("authorization")) {
+ req.auth = auth.checkAuthorization(req.headers.authorization, req.method, "navajo", config.authorizations[uri]);
+ validated = req.auth.validated;
+ }
+
+ if (!validated) {
+ return auth.generateAuthorization(res, "navajo", "digest");
+ }
+ }
+ }
+ }
+
if (config.plugins.hasOwnProperty(mime_type)) {
if (!plugins.hasOwnProperty(config.plugins[mime_type])) {
plugins[config.plugins[mime_type]] = require("./plugins/" + config.plugins[mime_type]);
View
9 navajo.conf
@@ -24,5 +24,14 @@
"application/x-httpd-php" : "php5-cgi",
"application/x-httpd-js" : "node",
"text/less" : "less"
+ },
+ "authorizations": {
+ "/core/" : {
+ "dev" : "developerpwd",
+ "adm" : "adminpwd"
+ },
+ "/test.json" : {
+ "user" : "password"
+ }
}
}

0 comments on commit 6ea6d51

Please sign in to comment.
Something went wrong with that request. Please try again.