231 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
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);
 | 
						|
    });
 | 
						|
  });
 | 
						|
}) |