Skip to content

Commit

Permalink
Oz endpoint relocation
Browse files Browse the repository at this point in the history
  • Loading branch information
Eran Hammer committed Nov 13, 2012
1 parent 5a4dacf commit 5c0305c
Showing 1 changed file with 13 additions and 216 deletions.
229 changes: 13 additions & 216 deletions lib/auth/oz.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
var Oz = require('oz');
var Utils = require('../utils');
var Err = require('../error');
var Types = require('joi').Types;


// Declare internals
Expand Down Expand Up @@ -34,9 +33,9 @@ exports.Scheme = internals.Scheme = function (server, options) {
// Add protocol endpoints

server.addRoutes([
{ method: 'POST', path: this.settings.appEndpoint, config: this.appEndpoint() },
{ method: 'POST', path: this.settings.reissueEndpoint, config: this.reissueEndpoint() },
{ method: 'POST', path: this.settings.rsvpEndpoint, config: this.rsvpEndpoint() }
{ method: 'POST', path: this.settings.appEndpoint, config: this._endpoint('app') },
{ method: 'POST', path: this.settings.reissueEndpoint, config: this._endpoint('reissue') },
{ method: 'POST', path: this.settings.rsvpEndpoint, config: this._endpoint('rsvp') }
]);

return this;
Expand All @@ -45,7 +44,7 @@ exports.Scheme = internals.Scheme = function (server, options) {

// Request an applicaiton ticket using Basic authentication

internals.Scheme.prototype.appEndpoint = function () {
internals.Scheme.prototype._endpoint = function (name) {

var self = this;

Expand All @@ -55,196 +54,15 @@ internals.Scheme.prototype.appEndpoint = function () {
},
handler: function (request) {

// Parse Basic authentication
Oz.endpoints[name](request.raw.req, request.payload, self.settings, function (err, response) {

var creds = self._basicAuth(request);
if (creds instanceof Error) {
return request.reply(new Oz.Error('invalid_request', 'Bad application authentication'));
}

// Load application

self.settings.loadAppFunc(creds.username, function (app) {

if (!app) {
return request.reply(new Oz.Error('invalid_client', 'Invalid application identifier or secret'));
}

// Validate application secret

if ((app.secret || '') !== (creds.password || '')) {
return request.reply(new Oz.Error('invalid_client', 'Invalid application identifier or secret'));
}

// Issue application ticket

Oz.ticket.issue(app, null, self.settings.encryptionPassword, {}, function (err, envelope) {

if (err) {
return request.reply(new Oz.Error('invalid_client', 'Failed to issue ticket: ' + err));
}

return request.reply(envelope);
});
});
}
};

return endpoint;
};


// Request a ticket reissue using the authenticating ticket

internals.Scheme.prototype.reissueEndpoint = function () {

var self = this;

var endpoint = {
schema: {
issueTo: Types.String(),
scope: Types.Array().includes(Types.String()).emptyOk()
},
auth: {
mode: 'required',
entity: 'any'
},
handler: function (request) {

var ticket = request.session;

var load = function () {

// Load ticket

self.settings.loadAppFunc(ticket.app, function (app) {

if (!app) {
return request.reply(new Oz.Error('invalid_client', 'Invalid application identifier or secret'));
}

if (!ticket.grant) {
return reissue(app);
}

self.settings.loadGrantFunc(ticket.grant, function (grant, ext) {

if (!grant ||
grant.app !== ticket.app ||
grant.user !== ticket.user ||
!grant.exp ||
grant.exp <= Date.now()) {

return request.reply(new Oz.Error('invalid_client', 'Invalid grant'));
}

return reissue(app, grant, ext);
});
});
};

var reissue = function (app, grant, ext) {

var options = {};

if (grant) {
options.grantExp = grant.exp;
}

if (request.payload.issueTo) {
// Need to check if the app has permission to delegate ///////////////////////////////////////////////////
options.issueTo = request.payload.issueTo;
}

if (request.payload.scope) {
// Check that scope is a subset of grant ///////////////////////////////////////
options.scope = request.payload.scope;
}

if (ext) {
options.ext = ext;
}

Oz.ticket.reissue(ticket, self.settings.encryptionPassword, options, function (err, envelope) {

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

return request.reply(envelope);
});
};

load();
}
};

return endpoint;
};


internals.Scheme.prototype.rsvpEndpoint = function () {

var self = this;

var endpoint = {
schema: {
rsvp: Types.String().required()
},
auth: {
mode: 'required',
entity: 'app'
},
handler: function (request) {

var ticket = request.session;
var now = Date.now();
if (err &&
err.wwwAuthenticateHeader) {

Oz.rsvp.parse(request.payload.rsvp, self.settings.encryptionPassword, function (err, envelope) {

if (err) {
return request.reply(new Oz.Error('invalid_client', 'Invalid rsvp: ' + err));
}

if (envelope.app !== ticket.app) {
return request.reply(new Oz.Error('invalid_client', 'Mismatching ticket and rsvp apps'));
request.raw.res.setHeader('WWW-Authenticate', err.wwwAuthenticateHeader);
}

if (envelope.exp <= now) {
return request.reply(new Oz.Error('invalid_client', 'Expired rsvp'));
}

self.settings.loadGrantFunc(envelope.grant, function (grant, ext) {

if (!grant ||
grant.app !== ticket.app ||
!grant.exp ||
grant.exp <= now) {

return request.reply(new Oz.Error('invalid_client', 'Invalid grant'));
}

self.settings.loadAppFunc(grant.app, function (app) {

if (!app) {
return request.reply(new Oz.Error('invalid_client', 'Invalid application identifier or secret'));
}

var options = {};
if (ext) {
options.ext = ext;
}

Oz.ticket.issue(app, grant, self.settings.encryptionPassword, options, function (err, envelope) {

if (err) {
return request.reply(new Oz.Error('invalid_client', 'Failed to issue ticket: ' + err));
}

return request.reply(envelope);
});
});
});
return request.reply(err || response);
});
}
};
Expand Down Expand Up @@ -294,14 +112,14 @@ internals.Scheme.prototype.authenticate = function (request, next) {

var entity = config.entity || 'user';

// User Mode: any
// Entity: any

if (entity === 'any') {
request.log(['auth']);
return next();
}

// User Mode: required
// Entity: required

if (entity === 'user') {
if (!ticket.user) {
Expand All @@ -323,7 +141,7 @@ internals.Scheme.prototype.authenticate = function (request, next) {
return next();
}

// User Mode: none
// Entity: none

if (entity === 'app') {
if (ticket.user) {
Expand All @@ -335,7 +153,7 @@ internals.Scheme.prototype.authenticate = function (request, next) {
return next();
}

// User Mode: unknown
// Entity: unknown

request.log(['auth', 'error'], 'Unknown entity mode: ' + entity);
return next(Err.internal('Unknown endpoint entity mode'));
Expand All @@ -349,24 +167,3 @@ internals.Scheme.prototype.authenticate = function (request, next) {
};


internals.Scheme.prototype._basicAuth = function (request) {

var authorization = request.raw.req.headers.authorization;
if (!authorization) {
return new Error('Request missing client authentication');
}

var parts = authorization.split(/\s+/);
if (parts.length !== 2) {
return new Error('Bad HTTP authentication header format: ' + authorization);
}

if (parts[0].toLowerCase() !== 'basic') {
return new Error('Incorrect HTTP authentication scheme: ' + parts[0]);
}

var credentials = new Buffer(parts[1], 'base64').toString().split(':');
return { username: credentials[0], password: credentials[1] };
};


0 comments on commit 5c0305c

Please sign in to comment.