зеркало из https://github.com/mozilla/hawk.git
Fix for #110 override of localStorage offset
This commit is contained in:
Родитель
0668873a2f
Коммит
d2212537fc
|
@ -105,7 +105,7 @@ hawk.client = {
|
|||
// Calculate payload hash
|
||||
|
||||
if (!artifacts.hash &&
|
||||
options.hasOwnProperty('payload')) {
|
||||
(options.payload || options.payload === '')) {
|
||||
|
||||
artifacts.hash = hawk.crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
|
||||
}
|
||||
|
@ -153,11 +153,12 @@ hawk.client = {
|
|||
return request.getResponseHeader ? request.getResponseHeader(name) : request.getHeader(name);
|
||||
};
|
||||
|
||||
if (getHeader('www-authenticate')) {
|
||||
var wwwAuthenticate = getHeader('www-authenticate');
|
||||
if (wwwAuthenticate) {
|
||||
|
||||
// Parse HTTP WWW-Authenticate header
|
||||
|
||||
var attributes = hawk.utils.parseAuthorizationHeader(getHeader('www-authenticate'), ['ts', 'tsm', 'error']);
|
||||
var attributes = hawk.utils.parseAuthorizationHeader(wwwAuthenticate, ['ts', 'tsm', 'error']);
|
||||
if (!attributes) {
|
||||
return false;
|
||||
}
|
||||
|
@ -174,13 +175,14 @@ hawk.client = {
|
|||
|
||||
// Parse HTTP Server-Authorization header
|
||||
|
||||
if (!getHeader('server-authorization') &&
|
||||
var serverAuthorization = getHeader('server-authorization');
|
||||
if (!serverAuthorization &&
|
||||
!options.required) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var attributes = hawk.utils.parseAuthorizationHeader(getHeader('server-authorization'), ['mac', 'ext', 'hash']);
|
||||
var attributes = hawk.utils.parseAuthorizationHeader(serverAuthorization, ['mac', 'ext', 'hash']);
|
||||
if (!attributes) {
|
||||
return false;
|
||||
}
|
||||
|
@ -203,7 +205,9 @@ hawk.client = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!options.hasOwnProperty('payload')) {
|
||||
if (!options.payload &&
|
||||
options.payload !== '') {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -330,7 +334,7 @@ hawk.crypto = {
|
|||
var hash = CryptoJS.algo[algorithm.toUpperCase()].create();
|
||||
hash.update('hawk.' + hawk.crypto.headerVersion + '.payload\n');
|
||||
hash.update(hawk.utils.parseContentType(contentType) + '\n');
|
||||
hash.update(payload || '');
|
||||
hash.update(payload);
|
||||
hash.update('\n');
|
||||
return hash.finalize().toString(CryptoJS.enc.Base64);
|
||||
},
|
||||
|
@ -359,9 +363,11 @@ hawk.utils = {
|
|||
|
||||
setStorage: function (storage) {
|
||||
|
||||
var offset = hawk.utils.storage.getItem('hawk_ntp_offset');
|
||||
hawk.utils.storage = storage;
|
||||
var ntpOffset = hawk.utils.getNtpOffset() || 0;
|
||||
hawk.utils.setNtpOffset(ntpOffset);
|
||||
if (offset) {
|
||||
hawk.utils.setNtpOffset(ntpOffset);
|
||||
}
|
||||
},
|
||||
|
||||
setNtpOffset: function (offset) {
|
||||
|
@ -377,7 +383,12 @@ hawk.utils = {
|
|||
|
||||
getNtpOffset: function () {
|
||||
|
||||
return parseInt(hawk.utils.storage.getItem('hawk_ntp_offset') || '0', 10);
|
||||
var offset = hawk.utils.storage.getItem('hawk_ntp_offset');
|
||||
if (!offset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return parseInt(offset, 10);
|
||||
},
|
||||
|
||||
now: function (localtimeOffsetMsec) {
|
||||
|
|
191
test/browser.js
191
test/browser.js
|
@ -558,6 +558,19 @@ describe('Browser', function () {
|
|||
done();
|
||||
});
|
||||
|
||||
it('returns a valid authorization header (null ext)', function (done) {
|
||||
|
||||
var credentials = {
|
||||
id: '123456',
|
||||
key: '2983d45yun89q',
|
||||
algorithm: 'sha256'
|
||||
};
|
||||
|
||||
var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain', ext: null }).field;
|
||||
expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="');
|
||||
done();
|
||||
});
|
||||
|
||||
it('returns a valid authorization header (uri object)', function (done) {
|
||||
|
||||
var credentials = {
|
||||
|
@ -683,10 +696,58 @@ describe('Browser', function () {
|
|||
expect(header.err).to.equal('Unknown algorithm');
|
||||
done();
|
||||
});
|
||||
|
||||
it('uses a pre-calculated payload hash', function (done) {
|
||||
|
||||
var credentials = {
|
||||
id: '123456',
|
||||
key: '2983d45yun89q',
|
||||
algorithm: 'sha256'
|
||||
};
|
||||
|
||||
var options = { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' };
|
||||
options.hash = Browser.crypto.calculatePayloadHash(options.payload, credentials.algorithm, options.contentType);
|
||||
var header = Browser.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', options).field;
|
||||
expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ext="Bazinga!", mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#authenticate', function () {
|
||||
|
||||
it('skips tsm validation when missing ts', function (done) {
|
||||
|
||||
var res = {
|
||||
headers: {
|
||||
'www-authenticate': 'Hawk error="Stale timestamp"'
|
||||
},
|
||||
getResponseHeader: function (header) {
|
||||
|
||||
return res.headers[header.toLowerCase()];
|
||||
}
|
||||
};
|
||||
|
||||
var credentials = {
|
||||
id: '123456',
|
||||
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
|
||||
algorithm: 'sha256',
|
||||
user: 'steve'
|
||||
};
|
||||
|
||||
var artifacts = {
|
||||
ts: 1402135580,
|
||||
nonce: 'iBRB6t',
|
||||
method: 'GET',
|
||||
resource: '/resource/4?filter=a',
|
||||
host: 'example.com',
|
||||
port: '8080',
|
||||
ext: 'some-app-data'
|
||||
};
|
||||
|
||||
expect(Browser.client.authenticate(res, credentials, artifacts)).to.equal(true);
|
||||
done();
|
||||
});
|
||||
|
||||
it('returns false on invalid header', function (done) {
|
||||
|
||||
var res = {
|
||||
|
@ -781,7 +842,7 @@ describe('Browser', function () {
|
|||
done();
|
||||
});
|
||||
|
||||
it('should fail on invalid WWW-Authenticate header format', function (done) {
|
||||
it('errors on invalid WWW-Authenticate header format', function (done) {
|
||||
|
||||
var res = {
|
||||
headers: {
|
||||
|
@ -797,7 +858,7 @@ describe('Browser', function () {
|
|||
done();
|
||||
});
|
||||
|
||||
it('should fail on invalid WWW-Authenticate header format', function (done) {
|
||||
it('errors on invalid WWW-Authenticate header format', function (done) {
|
||||
|
||||
var credentials = {
|
||||
id: '123456',
|
||||
|
@ -822,6 +883,7 @@ describe('Browser', function () {
|
|||
});
|
||||
|
||||
describe('#message', function () {
|
||||
|
||||
it('generates an authorization then successfully parse it', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
@ -838,7 +900,19 @@ describe('Browser', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fail on missing host', function (done) {
|
||||
it('generates an authorization using custom nonce/timestamp', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: credentials, nonce: 'abc123', timestamp: 1398536270957 });
|
||||
expect(auth).to.exist;
|
||||
expect(auth.nonce).to.equal('abc123');
|
||||
expect(auth.ts).to.equal(1398536270957);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on missing host', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
|
@ -848,14 +922,105 @@ describe('Browser', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fail on missing credentials', function (done) {
|
||||
it('errors on invalid host', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var auth = Browser.client.message(5, 8080, 'some message', { credentials: credentials });
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on missing port', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var auth = Browser.client.message('example.com', 0, 'some message', { credentials: credentials });
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on invalid port', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var auth = Browser.client.message('example.com', 'a', 'some message', { credentials: credentials });
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on missing message', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var auth = Browser.client.message('example.com', 8080, undefined, { credentials: credentials });
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on null message', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var auth = Browser.client.message('example.com', 8080, null, { credentials: credentials });
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on invalid message', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var auth = Browser.client.message('example.com', 8080, 5, { credentials: credentials });
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on missing credentials', function (done) {
|
||||
|
||||
var auth = Browser.client.message('example.com', 8080, 'some message', {});
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fail on invalid algorithm', function (done) {
|
||||
it('errors on missing options', function (done) {
|
||||
|
||||
var auth = Browser.client.message('example.com', 8080, 'some message');
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
|
||||
it('errors on invalid credentials (id)', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var creds = Hoek.clone(credentials);
|
||||
delete creds.id;
|
||||
var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: creds });
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on invalid credentials (key)', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var creds = Hoek.clone(credentials);
|
||||
delete creds.key;
|
||||
var auth = Browser.client.message('example.com', 8080, 'some message', { credentials: creds });
|
||||
expect(auth).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors on invalid algorithm', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
|
@ -870,7 +1035,7 @@ describe('Browser', function () {
|
|||
|
||||
describe('#authenticateTimestamp', function (done) {
|
||||
|
||||
it('should validate a timestamp', function (done) {
|
||||
it('validates a timestamp', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
|
@ -880,7 +1045,19 @@ describe('Browser', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should detect a bad timestamp', function (done) {
|
||||
it('validates a timestamp without updating local time', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
var offset = Browser.utils.getNtpOffset();
|
||||
var tsm = Hawk.crypto.timestampMessage(credentials, 10000);
|
||||
expect(Browser.client.authenticateTimestamp(tsm, credentials, false)).to.equal(true);
|
||||
expect(offset).to.equal(Browser.utils.getNtpOffset());
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('detects a bad timestamp', function (done) {
|
||||
|
||||
credentialsFunc('123456', function (err, credentials) {
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче