From e73f62bfbbfe73aa4093ef0147c81093ca5a6ac7 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Mon, 12 Nov 2012 00:41:02 -0800 Subject: [PATCH 1/4] Initial Oz auth interface endpoints --- lib/auth/index.js | 41 +++++ lib/auth/oz.js | 447 +++++++++++++++++++++++++++------------------- lib/request.js | 16 +- lib/server.js | 7 + 4 files changed, 323 insertions(+), 188 deletions(-) create mode 100755 lib/auth/index.js diff --git a/lib/auth/index.js b/lib/auth/index.js new file mode 100755 index 000000000..cbafc516a --- /dev/null +++ b/lib/auth/index.js @@ -0,0 +1,41 @@ +// Load modules + +var Oz = require('./oz'); +var Utils = require('../utils'); +var Err = require('../error'); +var Log = require('../log'); + + +// Declare internals + +var internals = {}; + + +exports = module.exports = internals.Auth = function (server, options) { + + Utils.assert(this.constructor === internals.Auth, 'Auth must be instantiated using new'); + Utils.assert(options, 'Invalid options'); + Utils.assert(options.scheme, 'Missing scheme'); + + // Built-in schemes + + if (options.scheme === 'oz') { + this.scheme = new Oz.Scheme(server, options); + } + else if (options.scheme === 'basic') { + + } + else { + + } + + Log.event(['info', 'config', 'auth'], server.settings.nickname + ': Authentication enabled'); + return this; +}; + + +internals.Auth.prototype.authenticate = function (request, next) { + + return this.scheme.authenticate(request, next); +}; + diff --git a/lib/auth/oz.js b/lib/auth/oz.js index bf6b800fa..6bc3c3902 100755 --- a/lib/auth/oz.js +++ b/lib/auth/oz.js @@ -1,8 +1,8 @@ // Load modules var Oz = require('oz'); -var Utils = require('./utils'); -var Err = require('./error'); +var Utils = require('../utils'); +var Err = require('../error'); var Types = require('joi').Types; @@ -11,77 +11,262 @@ var Types = require('joi').Types; var internals = {}; -// Defaults +exports.Scheme = internals.Scheme = function (server, options) { -exports.defaults = { - tokenEndpoint: '/oauth/token', - encryptionPassword: null, - ozSettings: null, + Utils.assert(this.constructor === internals.Scheme, 'Scheme must be instantiated using new'); + Utils.assert(options, 'Invalid options'); + Utils.assert(options.scheme === 'oz', 'Wrong scheme'); + Utils.assert(options.encryptionPassword, 'Missing encryption password'); + Utils.assert(options.loadAppFunc && options.loadGrantFunc, 'Missing required methods in configuration'); - verifyTicketFunc: null, - getAppFunc: null, - checkAuthorizationFunc: null, - extensionFunc: null, + this.settings = Utils.clone(options); // Options can be reused + this.settings.appEndpoint = this.settings.appEndpoint || '/oz/app'; + this.settings.reissueEndpoint = this.settings.reissueEndpoint || '/oz/reissue'; + this.settings.rsvpEndpoint = this.settings.rsvpEndpoint || '/oz/rsvp'; + this.settings.isHttps = !!server.settings.tls; - tos: { - min: 'none' // Format: YYYYMMDD (e.g. '19700101') + // Setup Oz environment + + if (this.settings.ozSettings) { + Oz.settings.set(this.settings.ozSettings); } + + // 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() } + ]); + + return this; }; -// Setup endpoints +// Request an applicaiton ticket using Basic authentication + +internals.Scheme.prototype.appEndpoint = function () { + + var self = this; + + var endpoint = { + auth: { + mode: 'none' + }, + handler: function (request) { + + // Parse Basic authentication + + var creds = self._basicAuth(request); + if (creds instanceof Error) { + return request.reply(new Oz.Error('invalid_request', 'Bad application authentication')); + } -exports.setup = function (server) { + // Load application - if (server.settings.auth) { - Utils.assert(server.settings.auth.tokenEndpoint && - server.settings.auth.verifyTicketFunc && - server.settings.auth.getAppFunc && - server.settings.auth.checkAuthorizationFunc && - server.settings.auth.encryptionPassword, 'Invalid authentication configuration'); + 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)); + } - if (server.settings.auth.ozSettings) { - Oz.settings.set(server.settings.auth.ozSettings); + return request.reply(envelope); + }); + }); } + }; + + return endpoint; +}; - server.addRoute({ - method: 'POST', - path: server.settings.auth.tokenEndpoint, - config: exports.token - }); - Log.event(['info', 'config'], server.settings.nickname + ': Authentication enabled'); - } +// 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.issuedTo) { + // Need to check if the app has permission to delegate /////////////////////////////////////////////////// + options.issuedFor = request.payload.issuedTo; + } + + 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 callback(null, envelope); + }); + }; + + load(); + } + }; + + return endpoint; }; -// Token Authentication +internals.Scheme.prototype.rsvpEndpoint = function () { -exports.authenticate = function (request, next) { + var self = this; - /* + var endpoint = { + schema: { + rsvp: Types.String().required() + }, + auth: { + mode: 'required', + entity: 'app' + }, + handler: function (request) { - if (this.config.auth.mode !== 'none') { - this.config.auth.scope = this.config.auth.scope || null; - this.config.auth.tos = this.config.auth.tos || this.server.settings.auth.tos.min; - this.config.auth.entity = this.config.auth.entity || 'user'; + var ticket = request.session; + var now = Date.now(); - Utils.assert(['user', 'app', 'any'].indexOf(this.config.auth.entity) !== -1, 'Unknown authentication entity: ' + this.config.auth.entity); - } - - */ + 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 (request._route.config.auth.mode === 'none') { - return next(); - } + if (envelope.app !== ticket.app) { + return request.reply(new Oz.Error('invalid_client', 'Mismatching ticket and rsvp apps')); + } + + 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 endpoint; +}; + + +// Token Authentication + +internals.Scheme.prototype.authenticate = function (request, next) { + + var self = this; var validate = function (err, ticket, attributes) { + var config = request._route.config.auth; + // Unauthenticated if (err) { - if (request._route.config.auth.mode === 'optional' && + if (config.mode === 'optional' && !request.raw.req.headers.authorization) { request.session = null; @@ -100,34 +285,37 @@ exports.authenticate = function (request, next) { // Check scope - if (request._route.config.auth.scope && - request.session.scope.indexOf(request._route.config.auth.scope) === -1) { + if (config.scope && + ticket.scope.indexOf(config.scope) === -1) { - request.log(['auth', 'error', 'scope'], { got: request.session.scope, need: request._route.config.auth.scope }); - return next(Err.forbidden('Insufficient scope (\'' + request._route.config.auth.scope + '\' expected for application ' + request.session.app + ')')); + request.log(['auth', 'error', 'scope'], { got: ticket.scope, need: config.scope }); + return next(Err.forbidden('Insufficient scope (\'' + config.scope + '\' expected for application ' + ticket.app + ')')); } + var entity = config.entity || 'user'; + // User Mode: any - if (request._route.config.auth.entity === 'any') { + if (entity === 'any') { request.log(['auth']); return next(); } // User Mode: required - if (request._route.config.auth.entity === 'user') { - if (!request.session.user) { + if (entity === 'user') { + if (!ticket.user) { request.log(['auth', 'error'], 'User ticket required'); return next(Err.forbidden('Application ticket cannot be used on a user endpoint')); } // Check TOS - if (request._route.config.auth.tos !== 'none' && - (!request.session.ext || !request.session.ext.tos || request.session.ext.tos < request._route.config.auth.tos)) { + var tos = (config.hasOwnProperty('tos') ? config.tos : self.settings.tos); + if (tos && + (!ticket.ext || !ticket.ext.tos || ticket.ext.tos < tos)) { - request.log(['auth', 'error'], 'Insufficient TOS'); + request.log(['auth', 'error', 'tos'], { min: tos, user: ticket.ext && ticket.ext.tos }); return next(Err.forbidden('Insufficient TOS accepted')); } @@ -137,8 +325,8 @@ exports.authenticate = function (request, next) { // User Mode: none - if (request._route.config.auth.entity === 'app') { - if (request.session.user) { + if (entity === 'app') { + if (ticket.user) { request.log(['auth', 'error'], 'App ticket required'); return next(Err.forbidden('User ticket cannot be used on an application endpoint')); } @@ -149,147 +337,36 @@ exports.authenticate = function (request, next) { // User Mode: unknown - request.log(['auth', 'error'], 'Unknown entity mode: ' + request._route.config.auth.entity); + request.log(['auth', 'error'], 'Unknown entity mode: ' + entity); return next(Err.internal('Unknown endpoint entity mode')); }; - + if (request.session) { return validate(null, request.session, null); } - Oz.Request.authenticate(request.raw.req, request.server.settings.auth.encryptionPassword, { isHttps: request.server.settings.tls }, validate); + Oz.request.authenticate(request.raw.req, this.settings.encryptionPassword, { isHttps: this.settings.isHttps }, validate); }; -// Get session token - -exports.token = { - schema: { - grant_type: Types.String(), - client_id: Types.String().required(), - client_secret: Types.String().emptyOk(), - grant: Types.String() - }, - auth: { - mode: 'optional', - entity: 'any' - }, - handler: function (request) { - - var serverSettings = request.server.settings.auth; - - // Load app information - - if (!request.payload.grant_type) { - return issue(null, app); - } - else if (request.payload.grant_type === 'rsvp') { - - if (!request.payload.grant) { - return request.reply(new Oz.Error('invalid_request', 'Missing grant')); - } +internals.Scheme.prototype._basicAuth = function (request) { - serverSettings.verifyTicketFunc(request.payload.grant, function (app, user) { - - if (!app || !user) { - return request.reply(new Oz.Error('invalid_grant')); - } - - return issue(user, app); - }); - } - else if (serverSettings.extensionFunc) { - serverSettings.extensionFunc(ticket, function (app, user, action) { - - if (!app || !user) { - return request.reply(new Oz.Error('invalid_grant')); - } - - return issue(user, app, action); - }); - } - else { - // Unsupported grant type - return request.reply(new Oz.Error('unsupported_grant_type', 'Unknown or unsupported grant type')); - } - - - serverSettings.getAppFunc(request.payload.client_id, function (app) { - - if (!app) { - return request.reply(new Oz.Error('invalid_client', 'Invalid application identifier or secret')); - } - - // Check app secret - - if ((app.secret || '') !== (request.payload.client_secret || '')) { - // Bad app authentication - return request.reply(new Oz.Error('invalid_client', 'Invalid application identifier or secret')); - } - - }); - - function issue(user, app, customResponseFields) { - - var generate = function (grant) { - - // Issue a new token - - var ticketAttr = { - app: { - id: app.id, - scope: app.scope - }, - options: {} - }; - - if (user) { - ticketAttr.user = { - id: user.id, - rsvp: user.rsvp - }; - ticketAttr.options.ext = { - tos: user.tos - }; - } - - Oz.Ticket.generate(ticketAttr.app, ticketAttr.user, request.server.settings.auth.encryptionPassword, ticketAttr.options, function (err, ticket) { - - if (err) { - return request.reply(err); - } - - if (user) { - ticket.x_tos = ticketAttr.options.ext.tos - } - - if (grant) { - ticket.rsvp = grant; - } - - Utils.merge(ticket, customResponseFields); - return request.reply(ticket); - }); - }; - - // Application ticket - - if (!user) { - return generate(); - } - - // User ticket - - serverSettings.checkAuthorizationFunc(request.session, app, user, function (err, rsvp) { + var authorization = request.raw.req.headers.authorization; + if (!authorization) { + return new Error('Request missing client authentication'); + } - if (err) { - return request.reply(err); - } + var parts = authorization.split(/\s+/); + if (parts.length !== 2) { + return new Error('Bad HTTP authentication header format: ' + authorization); + } - return generate(rsvp); - }); - } + 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] }; }; diff --git a/lib/request.js b/lib/request.js index 9e0396376..55c8ec55a 100755 --- a/lib/request.js +++ b/lib/request.js @@ -18,8 +18,6 @@ var Cache = require('./cache'); var internals = {}; -// Create and configure server instance - exports = module.exports = internals.Request = function (server, req, res, options) { var now = Date.now(); // Take measurement as soon as possible @@ -49,7 +47,7 @@ exports = module.exports = internals.Request = function (server, req, res, optio // params // rawBody // payload - // session: { app, scope, user, tos } + // session: { app, scope, user, ext.tos } // setUrl() // setMethod() @@ -225,6 +223,7 @@ internals.Request.prototype._execute = function (route) { var funcs = [ // ext.onRequest() in Server internals.processDebug, + internals.authenticate, Validation.query, Payload.read, Validation.payload, @@ -264,6 +263,17 @@ internals.Request.prototype._execute = function (route) { }; +internals.authenticate = function (request, next) { + + var config = request._route.config.auth; + if (config.mode === 'none') { + return next(); + } + + return request.server.auth.authenticate(request, next); +}; + + internals.Request.prototype._decorate = function (callback) { var self = this; diff --git a/lib/server.js b/lib/server.js index 8188a6a98..bd27f03df 100755 --- a/lib/server.js +++ b/lib/server.js @@ -16,6 +16,7 @@ var Route = require('./route'); var Debug = require('./debug'); var Docs = require('./docs'); var Batch = require('./batch'); +var Auth = require('./auth'); // Declare internals @@ -118,6 +119,12 @@ module.exports = internals.Server = function (/* host, port, options */) { this.cache = null; } + // Authentication + + if (this.settings.auth) { + this.auth = new Auth(this, this.settings.auth); + } + // Setup debug endpoint if (this.settings.debug) { From 63903581d4fe9e3b97e039fde89f945100577341 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Mon, 12 Nov 2012 14:56:24 -0800 Subject: [PATCH 2/4] Typo --- lib/auth/oz.js | 2 +- lib/request.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/auth/oz.js b/lib/auth/oz.js index 6bc3c3902..3a67de446 100755 --- a/lib/auth/oz.js +++ b/lib/auth/oz.js @@ -171,7 +171,7 @@ internals.Scheme.prototype.reissueEndpoint = function () { return callback(err); } - return callback(null, envelope); + return request.reply(envelope); }); }; diff --git a/lib/request.js b/lib/request.js index 55c8ec55a..c26f0608a 100755 --- a/lib/request.js +++ b/lib/request.js @@ -47,7 +47,7 @@ exports = module.exports = internals.Request = function (server, req, res, optio // params // rawBody // payload - // session: { app, scope, user, ext.tos } + // session: { id, app, scope, user, ext.tos } // setUrl() // setMethod() From 5e42bafe41a5c009d757eff3e1e4930cc0bdc1e6 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Mon, 12 Nov 2012 19:27:22 -0800 Subject: [PATCH 3/4] First working Oz implementation --- lib/auth/oz.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/auth/oz.js b/lib/auth/oz.js index 3a67de446..d84a4adb6 100755 --- a/lib/auth/oz.js +++ b/lib/auth/oz.js @@ -151,9 +151,9 @@ internals.Scheme.prototype.reissueEndpoint = function () { options.grantExp = grant.exp; } - if (request.payload.issuedTo) { + if (request.payload.issueTo) { // Need to check if the app has permission to delegate /////////////////////////////////////////////////// - options.issuedFor = request.payload.issuedTo; + options.issueTo = request.payload.issueTo; } if (request.payload.scope) { From 9ea8bbd68ea80487ecb772725b159da530e556d4 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Tue, 13 Nov 2012 11:44:41 -0800 Subject: [PATCH 4/4] Oz endpoint relocation --- lib/auth/oz.js | 229 +++---------------------------------------------- 1 file changed, 13 insertions(+), 216 deletions(-) diff --git a/lib/auth/oz.js b/lib/auth/oz.js index d84a4adb6..0134fc250 100755 --- a/lib/auth/oz.js +++ b/lib/auth/oz.js @@ -3,7 +3,6 @@ var Oz = require('oz'); var Utils = require('../utils'); var Err = require('../error'); -var Types = require('joi').Types; // Declare internals @@ -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; @@ -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; @@ -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); }); } }; @@ -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) { @@ -323,7 +141,7 @@ internals.Scheme.prototype.authenticate = function (request, next) { return next(); } - // User Mode: none + // Entity: none if (entity === 'app') { if (ticket.user) { @@ -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')); @@ -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] }; -}; - -