var fs = require('fs');
var path = require('path');
var jwt = require('jsonwebtoken');
module.exports = {
loadPriority: 1500,
startPriority: 1500,
stopPriority: 1000,
initialize: function(api, next) {
api.auth = {};
// if the encryption method is RS or ES, then we need key files, else just use api.config.auth.secretOrPrivateKey
if(api.config.auth.tokenAlgorithm.indexOf('HS') != 0) {
api.auth.privateKey = fs.readFileSync(path.join(__dirname, '../', api.config.auth.secretOrPrivateKey));
api.auth.publicKey = fs.readFileSync(path.join(__dirname, '../', api.config.auth.publicKey));
}
else {
api.auth.privateKey = api.config.auth.secretOrPrivateKey;
api.auth.publicKey = api.config.auth.secretOrPrivateKey;
}
// TODO: load and confirm the configured providers in /config/auth.js
// check if there is a protocol, and if it is a known type, and then
// if the properties are defined and valid for each protocol
// decrypts and verifies the token
api.auth.isAuthenticated = function(data) {
var headers = data.connection.rawConnection.req.headers;
// verify if we have an Authorization header and it contains a Bearer token
if( (!headers.authorization) || (headers.authorization.indexOf('Bearer') != 0) ) {
return 'No proper authorization header found.';
}
var payload;
try {
payload = jwt.verify(headers.authorization.substring(7), api.auth.publicKey, {issuer: api.config.auth.issuer});
}
catch(err) {
if(err instanceof jwt.TokenExpiredError) {
return 'Token expired.';
}
else if(err instanceof jwt.JsonWebTokenError) {
return 'Bad token (' + err.message + ').';
}
else {
return 'Token cannot be verified.';
}
return 'Unknown JWT error.';
}
api.lodash.assign(data.params, payload);
return null;
}
var authVerifier = {
name: 'authVerifier',
global: false,
priority: 1500,
preProcessor: function(data, next) {
var err = null;
api.log('authVerifier::data.params','info',data.params);
// check if we already authenticated; basically do we have a valid, non-expired token
var result = api.auth.isAuthenticated(data);
if (result === null) {
return next(err);
}
// else indicate user must authenticate
err = new Error('Please authenticate before accessing this function: ' + result);
return next(err);
}
};
api.actions.addMiddleware(authVerifier);
next();
},
start: function(api, next) {
next();
},
stop: function(api, next) {
next();
}
}
module.exports = {
loadPriority: 1550,
startPriority: 1550,
stopPriority: 1000,
initialize: function(api, next) {
// add a preprocessor that checks route used vs. permissions in DB
var rbacChecker = {
name: 'rbacChecker',
global: false,
priority: 1550,
preProcessor: function(data, next) {
var err = null;
api.log('rbacChecker::data.params','info',data.params);
// token parser should have put user id in connection.params; use it to check authorization for endpoint
api.models.operator.find({
where: { id: data.connection.params.id, isLocked: false, $or: [ {deletedAt: {$gt: (new Date())}}, {deletedAt: null} ] },
include: [
{ model: api.models.permission,
include: [
{ model: api.models.activity,
include: [
{ model: api.models.target, where: { name: data.connection.rawConnection.parsedURL.pathname } },
{ model: api.models.operation, where: { verb: data.connection.rawConnection.method } }
]
}
]
}
]
})
.then(function(operator) {
if(!!operator) {
// approved
next(err);
}
else {
// not approved
api.log('User was not found as approved for action.', 'info', { id: data.connection.params.id, name: data.connection.rawConnection.parsedURL.pathname, verb: data.connection.rawConnection.method } );
err = new Error('You are not authorized for this action.');
next(err);
}
})
.catch(function(e) {
// error (hence not approved)
api.log(e, 'error', { id: data.connection.params.id, name: data.connection.rawConnection.parsedURL.pathname, verb: data.connection.rawConnection.method } );
err = new Error('You are not authorized for this action.');
next(err);
});
}
};
api.actions.addMiddleware(rbacChecker);
next();
},
start: function(api, next) {
next();
},
stop: function(api, next) {
next();
}
}
exports.action = {
name: 'getWorkOrders',
description: 'getWorkOrders',
middleware: ['authVerifier','rbacChecker'],
blockedConnectionTypes: [],
outputExample: {},
matchExtensionMimeType: false,
version: 1.0,
toDocument: true,
inputs: {},
run: function(api, data, next) {
var err = null;
api.log('getWorkOrders::data.params', 'info', data.params);
return next(err);
}
};
2015-05-07 15:22:20 - info: authVerifier::data.params action=getWorkOrders, apiVersion=1
2015-05-07 15:22:20 - info: rbacChecker::data.params action=getWorkOrders, apiVersion=1, first_name=Super, last_name=Admin, email=superadmin@commercialservices.com, id=1, iat=1430934095, exp=1431538895, iss=AEX-Server
2015-05-07 15:22:20 - info: getWorkOrders::data.params action=getWorkOrders, apiVersion=1
...