You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
7.5 KiB
231 lines
7.5 KiB
4 weeks ago
|
var needle = require('../'),
|
||
|
auth = require('../lib/auth'),
|
||
|
sinon = require('sinon'),
|
||
|
should = require('should'),
|
||
|
http = require('http'),
|
||
|
helpers = require('./helpers');
|
||
|
|
||
|
var createHash = require('crypto').createHash;
|
||
|
|
||
|
function md5(string) {
|
||
|
return createHash('md5').update(string).digest('hex');
|
||
|
}
|
||
|
|
||
|
function parse_header(header) {
|
||
|
var challenge = {},
|
||
|
matches = header.match(/([a-z0-9_-]+)="?([a-z0-9=\/\.@\s-\+]+)"?/gi);
|
||
|
|
||
|
for (var i = 0, l = matches.length; i < l; i++) {
|
||
|
var parts = matches[i].split('='),
|
||
|
key = parts.shift(),
|
||
|
val = parts.join('=').replace(/^"/, '').replace(/"$/, '');
|
||
|
|
||
|
challenge[key] = val;
|
||
|
}
|
||
|
|
||
|
return challenge;
|
||
|
}
|
||
|
|
||
|
describe('auth_digest', function() {
|
||
|
describe('With qop (RFC 2617)', function() {
|
||
|
it('should generate a proper header', function() {
|
||
|
// from https://tools.ietf.org/html/rfc2617
|
||
|
var performDigest = function() {
|
||
|
var header = 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"';
|
||
|
var user = 'Mufasa';
|
||
|
var pass = 'Circle Of Life';
|
||
|
var method = 'get';
|
||
|
var path = '/dir/index.html';
|
||
|
|
||
|
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||
|
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||
|
|
||
|
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||
|
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||
|
var expectedResponse = md5([
|
||
|
ha1,
|
||
|
parsedUpdatedHeader.nonce,
|
||
|
parsedUpdatedHeader.nc,
|
||
|
parsedUpdatedHeader.cnonce,
|
||
|
parsedUpdatedHeader.qop,
|
||
|
ha2
|
||
|
].join(':'));
|
||
|
|
||
|
return {
|
||
|
header: updatedHeader,
|
||
|
parsed: parsedUpdatedHeader,
|
||
|
expectedResponse: expectedResponse,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const result = performDigest();
|
||
|
|
||
|
(result.header).should
|
||
|
.match(/qop="auth"/)
|
||
|
.match(/uri="\/dir\/index.html"/)
|
||
|
.match(/opaque="5ccc069c403ebaf9f0171e9517f40e41"/)
|
||
|
.match(/realm="testrealm@host\.com"/)
|
||
|
.match(/response=/)
|
||
|
.match(/nc=/)
|
||
|
.match(/nonce=/)
|
||
|
.match(/cnonce=/);
|
||
|
|
||
|
(result.parsed.response).should.be.eql(result.expectedResponse);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('With plus character in nonce header', function() {
|
||
|
it('should generate a proper header', function() {
|
||
|
// from https://tools.ietf.org/html/rfc2617
|
||
|
var performDigest = function() {
|
||
|
var header = 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f6+00bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"';
|
||
|
var user = 'Mufasa';
|
||
|
var pass = 'Circle Of Life';
|
||
|
var method = 'get';
|
||
|
var path = '/dir/index.html';
|
||
|
|
||
|
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||
|
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||
|
|
||
|
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||
|
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||
|
var expectedResponse = md5([
|
||
|
ha1,
|
||
|
parsedUpdatedHeader.nonce,
|
||
|
parsedUpdatedHeader.nc,
|
||
|
parsedUpdatedHeader.cnonce,
|
||
|
parsedUpdatedHeader.qop,
|
||
|
ha2
|
||
|
].join(':'));
|
||
|
|
||
|
return {
|
||
|
header: updatedHeader,
|
||
|
parsed: parsedUpdatedHeader,
|
||
|
expectedResponse: expectedResponse,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const result = performDigest();
|
||
|
|
||
|
(result.header).should
|
||
|
.match(/nonce="dcd98b7102dd2f0e8b11d0f6\+00bfb0c093"/)
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('With colon character in nonce header', function() {
|
||
|
it('should generate a proper header', function() {
|
||
|
// from https://tools.ietf.org/html/rfc2617
|
||
|
var performDigest = function() {
|
||
|
var header = 'Digest realm="IP Camera", charset="UTF-8", algorithm="MD5", nonce="636144c2:2970b5fdd41b5ac6b669848f43d2d22b", qop="auth"';
|
||
|
var user = 'Mufasa';
|
||
|
var pass = 'Circle Of Life';
|
||
|
var method = 'get';
|
||
|
var path = '/dir/index.html';
|
||
|
|
||
|
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||
|
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||
|
|
||
|
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||
|
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||
|
var expectedResponse = md5([
|
||
|
ha1,
|
||
|
parsedUpdatedHeader.nonce,
|
||
|
parsedUpdatedHeader.nc,
|
||
|
parsedUpdatedHeader.cnonce,
|
||
|
parsedUpdatedHeader.qop,
|
||
|
ha2
|
||
|
].join(':'));
|
||
|
|
||
|
return {
|
||
|
header: updatedHeader,
|
||
|
parsed: parsedUpdatedHeader,
|
||
|
expectedResponse: expectedResponse,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const result = performDigest();
|
||
|
|
||
|
(result.header).should
|
||
|
.match(/nonce="636144c2:2970b5fdd41b5ac6b669848f43d2d22b"/)
|
||
|
});
|
||
|
});
|
||
|
|
||
|
|
||
|
describe('With brackets in realm header', function() {
|
||
|
it('should generate a proper header', function() {
|
||
|
// from https://tools.ietf.org/html/rfc2617
|
||
|
var performDigest = function() {
|
||
|
var header = 'Digest qop="auth", realm="IP Camera(76475)", nonce="4e4449794d575269597a706b5a575935595441324d673d3d", stale="FALSE", Basic realm="IP Camera(76475)"';
|
||
|
var user = 'Mufasa';
|
||
|
var pass = 'Circle Of Life';
|
||
|
var method = 'get';
|
||
|
var path = '/dir/index.html';
|
||
|
|
||
|
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||
|
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||
|
|
||
|
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||
|
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||
|
var expectedResponse = md5([
|
||
|
ha1,
|
||
|
parsedUpdatedHeader.nonce,
|
||
|
parsedUpdatedHeader.nc,
|
||
|
parsedUpdatedHeader.cnonce,
|
||
|
parsedUpdatedHeader.qop,
|
||
|
ha2
|
||
|
].join(':'));
|
||
|
|
||
|
return {
|
||
|
header: updatedHeader,
|
||
|
parsed: parsedUpdatedHeader,
|
||
|
expectedResponse: expectedResponse,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const result = performDigest();
|
||
|
|
||
|
(result.header).should
|
||
|
.match(/realm="IP Camera\(76475\)"/)
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Without qop (RFC 2617)', function() {
|
||
|
it('should generate a proper header', function() {
|
||
|
// from https://tools.ietf.org/html/rfc2069
|
||
|
var performDigest = function() {
|
||
|
var header = 'Digest realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"';
|
||
|
var user = 'Mufasa';
|
||
|
var pass = 'Circle Of Life';
|
||
|
var method = 'get';
|
||
|
var path = '/dir/index.html';
|
||
|
|
||
|
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||
|
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||
|
|
||
|
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||
|
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||
|
var expectedResponse = md5([ha1, parsedUpdatedHeader.nonce, ha2].join(':'));
|
||
|
|
||
|
return {
|
||
|
header: updatedHeader,
|
||
|
parsed: parsedUpdatedHeader,
|
||
|
expectedResponse: expectedResponse,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const result = performDigest();
|
||
|
|
||
|
(result.header).should
|
||
|
.not.match(/qop=/)
|
||
|
.match(/uri="\/dir\/index.html"/)
|
||
|
.match(/opaque="5ccc069c403ebaf9f0171e9517f40e41"/)
|
||
|
.match(/realm="testrealm@host\.com"/)
|
||
|
.match(/response=/)
|
||
|
.not.match(/nc=/)
|
||
|
.match(/nonce=/)
|
||
|
.not.match(/cnonce=/);
|
||
|
|
||
|
(result.parsed.response).should.be.eql(result.expectedResponse);
|
||
|
});
|
||
|
});
|
||
|
})
|