Basic Authentication v NodeJS

Basic Authentication určitě znáte z Apache. Pomocí httpasswd se tím dá zaheslovat přístup k celému adresáři, respektive otevřít adresář jen pro ty, které uvedete v .htaccess (htpasswd).

Authentication
Stejného chování lze dosáhnout i v NodeJS:

var http = require('http');

var username = 'codingdefined',
    password = 'coding',
    realm = 'Coding Defined';

http.createServer(function (req, res) {

    var auth, login;

    if (!req.headers.authorization) {
        authenticateResponse(res);
        return;
    }

    auth = req.headers.authorization.replace(/^Basic /, '');
    auth = (new Buffer(auth, 'base64').toString('utf8'));
  
    login = auth.split(':');

    if (login[0] === username && login[1] === password) {
        res.end("Login Successful");
        return;
    }

    authenticateResponse(res);

}).listen(8052);

function authenticateResponse(res) {
    res.writeHead(401, {'WWW-Authenticate' : 'Basic realm="' + realm + '"'});
    res.end('Authorization required');
}

Problémem tohoto řešení je, že autentifikace probíha skrze Plain HTTP.

Vylepšení authentication pomocí cryptování

var http = require('http');
var crypto = require('crypto');

var username = 'codingdefined',
    password = 'coding',
    realm = 'Digest Authentication - Coding Defined',
    hasedMsg;

function hashFunction(message) {
    return crypto.createHash('md5').update(message).digest('hex');
}

hasedMsg = hashFunction(realm);

http.createServer(function (req, res) {

    var auth, login, digestAuth = {};

    if (!req.headers.authorization) {
        authenticateResponse(res);
        return;
    }

    auth = req.headers.authorization.replace(/^Digest /, '');
    auth = getAuth(auth);

    digestAuth.hashValue1 = hashFunction(auth.username + ':' + realm + ':' + password);
    digestAuth.hashValue2 = hashFunction(req.method + ':' + auth.uri);
    digestAuth.response = hashFunction([digestAuth.hashValue1, auth.nonce, auth.nc, auth.cnonce, auth.qop, digestAuth.hashValue2].join(':'));

    if (auth.response !== digestAuth.response) {
        authenticateResponse(res);
        return; 
    }

    res.end('Login Successful');

}).listen(8052);

function authenticateResponse(res) {
    res.writeHead(401, {'WWW-Authenticate' : 'Digest realm="' + realm + '"' + ', qop="auth",nonce="' + Math.random() + '"' + ',opaque="' + hasedMsg + '"'});
    res.end('Authorization required');
}

function getAuth(auth) {
    var authObj = {};

    auth.split(', ').forEach (function (value) {
        value = value.split('=');
        authObj[value[0]] = value[1].replace(/"/g, '');
    });

    return authObj;
}