Comparing version 0.0.1 to 0.0.2
@@ -61,3 +61,3 @@ // Load modules | ||
if (!req.headers.authorization) { | ||
return callback(new Error('No authentication'), false, null); | ||
return callback(new Error('Missing Authorization header'), false, null); | ||
} | ||
@@ -71,4 +71,4 @@ | ||
if (!attributes) { | ||
return callback(new Error('Incorrect authentication scheme'), false, null); | ||
if (attributes instanceof Error) { | ||
return callback(attributes, false, null); | ||
} | ||
@@ -87,3 +87,3 @@ | ||
var hostHeaderRegex = /^(?:(?:\r\n)?[\t ])*([^:]+)(?::(\d+))*(?:(?:\r\n)?[\t ])*$/; // Does not support IPv6 | ||
var hostHeaderRegex = /^(?:(?:\r\n)?[\t ])*([^:]+)(?::(\d+))?(?:(?:\r\n)?[\t ])*$/; // Does not support IPv6 | ||
var hostParts = hostHeader.match(hostHeaderRegex); | ||
@@ -185,11 +185,11 @@ | ||
var headerRegex = /^[Hh][Aa][Ww][Kk]\s+(.*)$/; | ||
var headerParts = headerRegex.exec(header); | ||
var headerRegex = /^([Hh][Aa][Ww][Kk])(?:\s+(.*))?$/; | ||
var headerParts = header.match(headerRegex); | ||
if (!headerParts || | ||
headerParts.length !== 2 || | ||
!headerParts[1]) { | ||
if (!headerParts) { | ||
return new Error('Incorrect scheme'); | ||
} | ||
// Invalid header format | ||
return null; | ||
if (!headerParts[2]) { | ||
return new Error('Invalid header format'); | ||
} | ||
@@ -200,3 +200,3 @@ | ||
var attributesRegex = /(id|ts|ext|mac)="([^"\\]*)"\s*(?:,\s*|$)/g; | ||
var verify = headerParts[1].replace(attributesRegex, function ($0, $1, $2) { | ||
var verify = headerParts[2].replace(attributesRegex, function ($0, $1, $2) { | ||
@@ -210,4 +210,3 @@ if (attributes[$1] === undefined) { | ||
if (verify !== '') { | ||
// Did not match all parts | ||
return null; | ||
return new Error('Unknown attributes'); | ||
} | ||
@@ -225,3 +224,3 @@ | ||
exports.getAuthorizationHeader = function (credentials, method, uri, host, port, ext) { | ||
exports.getAuthorizationHeader = function (credentials, method, uri, host, port, ext, timestamp) { | ||
@@ -238,20 +237,16 @@ // Check request | ||
// Generate nonce | ||
// Calculate signature | ||
var timestamp = Math.floor(((new Date()).getTime() / 1000)); | ||
timestamp = timestamp || Math.floor(((new Date()).getTime() / 1000)); | ||
var mac = exports.calculateMAC(credentials.key, credentials.algorithm, timestamp, method, uri, host, port, ext); | ||
// Calculate signature | ||
if (!mac) { | ||
return ''; | ||
} | ||
var mac = exports.calculateMAC(timestamp, nonce, method, uri, host, port, ext, credentials.key, credentials.algorithm); | ||
// Construct header | ||
var header = 'Hawk id="' + credentials.id + | ||
'", ts="' + timestamp + | ||
'", nonce="' + nonce + | ||
(ext ? '", ext="' + ext : '') + | ||
'", mac="' + mac + '"'; | ||
var header = 'Hawk id="' + credentials.id + '", ts="' + timestamp + (ext ? '", ext="' + ext : '') + '", mac="' + mac + '"'; | ||
return header; | ||
}; | ||
{ | ||
"name": "hawk", | ||
"description": "HTTP Hawk Authentication Scheme", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"author": "Eran Hammer <eran@hueniverse.com> (http://hueniverse.com)", | ||
"contributors":[ | ||
], | ||
"contributors": [], | ||
"repository": "git://github.com/hueniverse/hawk", | ||
@@ -19,4 +18,3 @@ "main": "index", | ||
}, | ||
"dependencies": { | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
@@ -23,0 +21,0 @@ "mocha": "1.x.x", |
396
test/hawk.js
@@ -5,3 +5,3 @@ // Load modules | ||
var should = require('should'); | ||
var Hawk = require('../lib/hawk'); | ||
var Hawk = process.env.TEST_COV ? require('../lib-cov/hawk') : require('../lib/hawk'); | ||
@@ -11,9 +11,44 @@ | ||
var credentialsFunc = function (id, callback) { | ||
var credentials = { | ||
id: id, | ||
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', | ||
algorithm: (id === '1' ? 'hmac-sha-1' : 'hmac-sha-256'), | ||
user: 'steve' | ||
}; | ||
return callback(null, credentials); | ||
}; | ||
it('should generate a header then successfully parse it', function (done) { | ||
var req = { | ||
headers: { | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
credentialsFunc('123456', function (err, credentials) { | ||
req.headers.authorization = Hawk.getAuthorizationHeader(credentials, req.method, req.url, 'example.com', 8080, null, 1353809207); | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.not.exist(err); | ||
credentials.user.should.equal('steve'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
describe('#authenticate', function () { | ||
it('should parse a valid authentication header', function (done) { | ||
it('should parse a valid authentication header (hmac-sha-1)', function (done) { | ||
var req = { | ||
headers: { | ||
authentication: 'Hawk id="123", ts="1353788437", mac="", ext="hello"', | ||
authorization: 'Hawk id="1", ts="1353788437", mac="lDdDLlWQhgcxTvYgzzLo3EZExog=", ext="hello"', | ||
host: 'example.com:8080' | ||
@@ -25,7 +60,223 @@ }, | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.not.exist(err); | ||
credentials.user.should.equal('steve'); | ||
done(); | ||
}); | ||
}); | ||
it('should parse a valid authentication header (hmac-sha-256)', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.not.exist(err); | ||
credentials.user.should.equal('steve'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on an invalid authentication header: wrong scheme', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Basic asdasdasdasd', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Incorrect scheme'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on an missing authorization header', function (done) { | ||
var req = { | ||
headers: { | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Missing Authorization header'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on an missing host header', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Missing Host header'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on an missing authorization attribute', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Missing attributes'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on an unknown authorization attribute', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk id="123", ts="1353788437", x="3", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Unknown attributes'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on an invalid authorization header format', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Invalid header format'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on an bad host header', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"', | ||
host: 'example.com:8080:90' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Bad Host header'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on credentialsFunc error', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
var credentialsFunc = function (id, callback) { | ||
return callback(new Error('Unknown user')); | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Unknown user'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on missing credentials', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
var credentialsFunc = function (id, callback) { | ||
return callback(null, null); | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Missing credentials'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on invalid credentials', function (done) { | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
var credentialsFunc = function (id, callback) { | ||
var credentials = { | ||
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', | ||
algorithm: 'hmac-sha-256', | ||
user: 'steve' | ||
@@ -37,6 +288,6 @@ }; | ||
Hawk.authenticate(req, encryptionPassword, {}, function (err, ticket, attributes) { | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.not.exist(err); | ||
attributes.ext.should.equal('"welcome"'); | ||
should.exist(err); | ||
err.message.should.equal('Invalid credentials'); | ||
done(); | ||
@@ -46,38 +297,58 @@ }); | ||
it('should return an error for an invalid authentication header', function (done) { | ||
it('should fail on unknown credentials algorithm', function (done) { | ||
// Note: the ticket.id already encodes all the other ticket attributes and they cannot be manually changed | ||
var req = { | ||
headers: { | ||
authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
var encryptionPassword = 'example'; | ||
var credentialsFunc = function (id, callback) { | ||
var ticket = { | ||
id: '4deee737c1810925ace5aa5292c4e761f2325eb1286bc5c69cbf00b3f5de3abc:eL5Zvd2wyIiMc-6Adk2SUy7i4TjZKLnV_KTUYnTri5Q:a5f7aa17320716247dd18fd87f04e7c0495980b3417d94185f0feb6c052e123e:p1BY4SLSY-5fjKuPSz_GwQ:UDPFp5jLSyYZmGrlD111XxNrZzhvWdU32k_05EjPm4vi0pynvYpGGXYTuuxlEj7hwUR4BOmFumASxvZJVRMMERhCtOjqBwUbU9L8MzI2wYYEryFImSwDkxZAamsG37KH6K1w-rTP-UgP8mVpmboA9-vzwRrlaPzvV19VS7kLGEUeDR8DFzwQpMl2lK-dw4KQPPmsKSGFzxlUO-9hpvWdU6lyTdMYAoy8MPTNCMT4NbgRrjitYV-6YKmhJNHMErzs', | ||
key: 'wrong', | ||
algorithm: 'sha256', | ||
app: '123' | ||
}; | ||
var credentials = { | ||
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', | ||
algorithm: 'hmac-sha-0', | ||
user: 'steve' | ||
}; | ||
var request = { | ||
method: 'GET', | ||
resource: '/path?query', | ||
host: 'example.com', | ||
port: 80 | ||
return callback(null, credentials); | ||
}; | ||
var attributes = { | ||
ext: '"welcome"' | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Unknown algorithm'); | ||
done(); | ||
}); | ||
}); | ||
it('should fail on unknown bad mac', function (done) { | ||
var req = { | ||
method: request.method, | ||
url: request.resource, | ||
headers: { | ||
authorization: Oz.request.generateHeader(request, ticket, attributes), | ||
host: request.host + ':' + request.port | ||
} | ||
authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcU4jlr7T/wuKe3dKijvTvSos=", ext="hello"', | ||
host: 'example.com:8080' | ||
}, | ||
method: 'GET', | ||
url: '/resource/4?filter=a' | ||
}; | ||
Oz.request.authenticate(req, encryptionPassword, {}, function (err, ticket, attributes) { | ||
var credentialsFunc = function (id, callback) { | ||
var credentials = { | ||
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', | ||
algorithm: 'hmac-sha-256', | ||
user: 'steve' | ||
}; | ||
return callback(null, credentials); | ||
}; | ||
Hawk.authenticate(req, credentialsFunc, {}, function (err, isAuthenticated, credentials) { | ||
should.exist(err); | ||
err.message.should.equal('Bad mac'); | ||
done(); | ||
@@ -87,3 +358,68 @@ }); | ||
}); | ||
describe('#getWWWAuthenticateHeader', function () { | ||
it('should return a valid Hawk header with error', function (done) { | ||
Hawk.getWWWAuthenticateHeader('boom').should.equal('Hawk error="boom"'); | ||
done(); | ||
}); | ||
it('should return a valid Hawk header without error', function (done) { | ||
Hawk.getWWWAuthenticateHeader().should.equal('Hawk'); | ||
done(); | ||
}); | ||
}); | ||
describe('#calculateMAC', function () { | ||
it('should return an empty value on unknown algorithm', function (done) { | ||
Hawk.calculateMAC('dasdfasdf', 'hmac-sha-0', Date.now() / 1000, 'GET', '/resource/something', 'example.com', 8080).should.equal(''); | ||
done(); | ||
}); | ||
}); | ||
describe('#getAuthorizationHeader', function () { | ||
it('should return a valid authorization header', function (done) { | ||
var credentials = { | ||
id: '123456', | ||
key: '2983d45yun89q', | ||
algorithm: 'hmac-sha-256' | ||
}; | ||
var header = Hawk.getAuthorizationHeader(credentials, 'POST', '/somewhere/over/the/rainbow', 'example.net', 443, 'Bazinga!', 1353809207); | ||
header.should.equal('Hawk id="123456", ts="1353809207", ext="Bazinga!", mac="LYUkYKYkQsQstqNQHcnAzDXce0oHsmS049rv4EalMb8="'); | ||
done(); | ||
}); | ||
it('should return an empty authorization header on invalid credentials', function (done) { | ||
var credentials = { | ||
key: '2983d45yun89q', | ||
algorithm: 'hmac-sha-256' | ||
}; | ||
var header = Hawk.getAuthorizationHeader(credentials, 'POST', '/somewhere/over/the/rainbow', 'example.net', 443, 'Bazinga!', 1353809207); | ||
header.should.equal(''); | ||
done(); | ||
}); | ||
it('should return an empty authorization header on invalid algorithm', function (done) { | ||
var credentials = { | ||
id: '123456', | ||
key: '2983d45yun89q', | ||
algorithm: 'hmac-sha-0' | ||
}; | ||
var header = Hawk.getAuthorizationHeader(credentials, 'POST', '/somewhere/over/the/rainbow', 'example.net', 443, 'Bazinga!', 1353809207); | ||
header.should.equal(''); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24786
486
2
1