Skip to content
This repository has been archived by the owner on Apr 16, 2019. It is now read-only.

Commit

Permalink
Fix reissue expiration bug. Closes #31
Browse files Browse the repository at this point in the history
  • Loading branch information
hueniverse committed Sep 22, 2015
1 parent 7176357 commit d6bd0e3
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 59 deletions.
35 changes: 6 additions & 29 deletions lib/endpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ exports.reissue = function (req, payload, options, callback) {
return callback(Boom.badRequest(error.message));
}

internals.authenticate(req, 'any', options, function (err, ticket) {
Server._authenticate(req, options.encryptionPassword, false, options, function (err, ticket, artifacts) {

if (err) {
return callback(err);
Expand Down Expand Up @@ -153,12 +153,16 @@ exports.rsvp = function (req, payload, options, callback) {
return callback(Boom.badRequest(error.message));
}

internals.authenticate(req, 'app', options, function (err, ticket) {
Server.authenticate(req, options.encryptionPassword, options, function (err, ticket, artifacts) {

if (err) {
return callback(err);
}

if (ticket.user) {
return callback(Hawk.utils.unauthorized('User ticket cannot be used on an application endpoint'));
}

Ticket.parse(payload.rsvp, options.encryptionPassword, options.ticket || {}, function (err, envelope) {

if (err) {
Expand Down Expand Up @@ -211,30 +215,3 @@ exports.rsvp = function (req, payload, options, callback) {
});
});
};


// Ticket authentication

internals.authenticate = function (req, entity, options, callback) {

Server.authenticate(req, options.encryptionPassword, options, function (err, credentials, artifacts) {

if (err) {
return callback(err);
}

// Entity: app

if (entity === 'app') {
if (credentials.user) {
return callback(Hawk.utils.unauthorized('User ticket cannot be used on an application endpoint'));
}

return callback(null, credentials);
}

// Entity: any

return callback(null, credentials);
});
};
65 changes: 36 additions & 29 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,42 @@ var internals = {};

exports.authenticate = function (req, encryptionPassword, options, callback) {

Hawk.server.authenticate(req, internals.credentialsFunc(encryptionPassword, options), options.hawk || {}, function (err, credentials, artifacts) {
return exports._authenticate(req, encryptionPassword, true, options, callback);
};


exports._authenticate = function (req, encryptionPassword, checkExpiration, options, callback) {

Hoek.assert(encryptionPassword, 'Invalid encryption password');
Hoek.assert(options, 'Invalid options object');

// Hawk credentials lookup method

var credentialsFunc = function (id, credsCallback) {

// Parse ticket id

Ticket.parse(id, encryptionPassword, options.ticket || {}, function (err, ticket) {

if (err) {
return credsCallback(err);
}

// Check expiration

if (checkExpiration &&
ticket.exp <= Hawk.utils.now()) {

return credsCallback(Hawk.utils.unauthorized('Expired ticket', { reason: 'expired' }));
}

return credsCallback(null, ticket);
});
};

// Hawk authentication

Hawk.server.authenticate(req, credentialsFunc, options.hawk || {}, function (err, credentials, artifacts) {

if (err) {
return callback(err);
Expand All @@ -38,31 +73,3 @@ exports.authenticate = function (req, encryptionPassword, options, callback) {
return callback(null, credentials, artifacts);
});
};


// Hawk credentialsFunc generator

internals.credentialsFunc = function (encryptionPassword, options) {

Hoek.assert(encryptionPassword, 'Invalid encryption password');

return function (id, callback) {

// Parse ticket id

Ticket.parse(id, encryptionPassword, options.ticket || {}, function (err, ticket) {

if (err) {
return callback(err);
}

// Check expiration

if (ticket.exp <= Hawk.utils.now()) {
return callback(Hawk.utils.unauthorized('Expired ticket', { reason: 'expired' }));
}

return callback(null, ticket);
});
};
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "oz",
"description": "Web Authorization Protocol",
"version": "1.0.1",
"version": "1.0.2",
"repository": "git://github.com/hueniverse/oz",
"main": "lib/index.js",
"keywords": [
Expand Down
156 changes: 156 additions & 0 deletions test/endpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,50 @@ describe('Endpoints', function () {
});
});

it('reissues expired ticket', function (done) {

var req = {
method: 'POST',
url: '/oz/app',
headers: {
host: 'example.com',
authorization: Oz.client.header('http://example.com/oz/app', 'POST', apps.social).field
}
};

var options = {
encryptionPassword: encryptionPassword,
loadAppFunc: function (id, callback) {

callback(null, apps[id]);
},
ticket: {
ttl: 5
}
};

Oz.endpoints.app(req, null, options, function (err, ticket) {

req = {
method: 'POST',
url: '/oz/reissue',
headers: {
host: 'example.com',
authorization: Oz.client.header('http://example.com/oz/reissue', 'POST', ticket).field
}
};

setTimeout(function () {

Oz.endpoints.reissue(req, {}, options, function (err, reissued) {

expect(err).to.not.exist();
done();
});
}, 10);
});
});

it('fails on app load error', function (done) {

var req = {
Expand Down Expand Up @@ -769,6 +813,118 @@ describe('Endpoints', function () {
});
});

it('errors on invalid authentication', function (done) {

var options = {
encryptionPassword: encryptionPassword,
loadAppFunc: function (id, callback) {

callback(null, apps[id]);
},
ticket: {
iron: Iron.defaults
}
};

var grant = {
id: 'a1b2c3d4e5f6g7h8i9j0',
app: appTicket.app,
user: 'john',
exp: Oz.hawk.utils.now() + 60000
};

Oz.ticket.rsvp(apps.social, grant, encryptionPassword, {}, function (err, rsvp) {

expect(err).to.not.exist();

options.loadGrantFunc = function (id, callback) {

callback(null, grant);
};

var payload = { rsvp: rsvp };

var req = {
method: 'POST',
url: '/oz/rsvp',
headers: {
host: 'example.com'
}
};

Oz.endpoints.rsvp(req, payload, options, function (err, ticket) {

expect(err).to.exist();
done();
});
});
});

it('errors on expired ticket', function (done) {

// App ticket

var req = {
method: 'POST',
url: '/oz/app',
headers: {
host: 'example.com',
authorization: Oz.client.header('http://example.com/oz/app', 'POST', apps.social).field
}
};

var options = {
encryptionPassword: encryptionPassword,
loadAppFunc: function (id, callback) {

callback(null, apps[id]);
},
ticket: {
ttl: 5
}
};

Oz.endpoints.app(req, null, options, function (err, applicationTicket) {

var grant = {
id: 'a1b2c3d4e5f6g7h8i9j0',
app: applicationTicket.app,
user: 'john',
exp: Oz.hawk.utils.now() + 60000
};

Oz.ticket.rsvp(apps.social, grant, encryptionPassword, {}, function (err, rsvp) {

expect(err).to.not.exist();

options.loadGrantFunc = function (id, callback) {

callback(null, grant);
};

var payload = { rsvp: rsvp };

req = {
method: 'POST',
url: '/oz/rsvp',
headers: {
host: 'example.com',
authorization: Oz.client.header('http://example.com/oz/rsvp', 'POST', applicationTicket).field
}
};

setTimeout(function () {

Oz.endpoints.rsvp(req, payload, options, function (err, ticket) {

expect(err).to.exist();
done();
});
}, 10);
});
});
});

it('errors on missing payload', function (done) {

Oz.endpoints.rsvp({}, null, {}, function (err, ticket) {
Expand Down

0 comments on commit d6bd0e3

Please sign in to comment.