1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | var
|
13 | auth = require('../lib/auth/manager'),
|
14 | query = require('./query'),
|
15 | util = require('util');
|
16 |
|
17 | function ErrorTemplate(err) {
|
18 | this.name = 'joola.io.engine Exception';
|
19 | this.code = 500;
|
20 | if (err.message) this.message = err.message; else this.message = err || '';
|
21 | if (err.stack) this.stack = err.stack; else this.stack = null;
|
22 | }
|
23 | ErrorTemplate.prototype = Error.prototype;
|
24 | exports.ErrorTemplate = ErrorTemplate
|
25 |
|
26 | function AuthErrorTemplate(err) {
|
27 | this.name = 'joola.io.engine Authentication Exception';
|
28 | this.code = 401;
|
29 | if (err.message) this.message = err.message; else this.message = err || '';
|
30 | if (err.stack) this.stack = err.stack; else this.stack = null;
|
31 | }
|
32 | AuthErrorTemplate.prototype = ErrorTemplate.prototype;
|
33 | exports.AuthErrorTemplate = AuthErrorTemplate;
|
34 |
|
35 | exports.responseError = function (err, req, res) {
|
36 | if (err.code && err.code == 401)
|
37 | res.status(401);
|
38 | else
|
39 | res.status(500);
|
40 | res.json({"error": err});
|
41 | };
|
42 |
|
43 | exports.responseSuccess = function (data, req, res) {
|
44 | var response = {};
|
45 |
|
46 | if (req.token)
|
47 | res.setHeader('joola-token', req.token);
|
48 |
|
49 | if (!req.params.minres) {
|
50 | response.id = require('node-uuid').v4();
|
51 | response.timestamp = new Date();
|
52 | response.success = true;
|
53 | response.details = {};
|
54 | response.details.request = req.debug;
|
55 | }
|
56 | response = _.extend(response, data);
|
57 |
|
58 | res.status(200);
|
59 |
|
60 |
|
61 | res.json(response);
|
62 | };
|
63 |
|
64 | exports.index = function (req, res) {
|
65 | res.end('ok');
|
66 | };
|
67 |
|
68 | exports.validateToken = function (req, res, callback) {
|
69 | var failed = function () {
|
70 | if (req.method == 'OPTIONS') {
|
71 | return callback(null, true);
|
72 | }
|
73 | else {
|
74 | joola.logger.warn('Detected a connection without a valid token accessing action: ' + req.params.resource + '/' + (req.params.action ? req.params.action : '') + '.');
|
75 | return callback(null, false);
|
76 | }
|
77 | };
|
78 |
|
79 | var validate = function (token) {
|
80 | auth.validateToken(token, function (user, _token) {
|
81 | if ((joola.config.auth.bypassToken != null && token == joola.config.auth.bypassToken) || joola.config.auth.store == 'none') {
|
82 | if (!_token)
|
83 | _token = '1234567890';
|
84 | user = {
|
85 | id: 1,
|
86 | displayName: 'Anonymous User',
|
87 | _roles: ['admin', 'user']
|
88 | };
|
89 | }
|
90 | if (user) {
|
91 | joola.logger.debug('Token [' + _token + '] validated.');
|
92 | req.user = user;
|
93 | req.token = _token;
|
94 |
|
95 | return callback(null, true);
|
96 | }
|
97 | else {
|
98 | joola.logger.error('Token [' + token + '] is invalid.');
|
99 | failed();
|
100 | }
|
101 | });
|
102 | };
|
103 |
|
104 | var approvedActions = [];
|
105 | approvedActions.push('login');
|
106 | approvedActions.push('loginSSO');
|
107 | approvedActions.push('loginNeeded');
|
108 | approvedActions.push('auth.checkToken');
|
109 |
|
110 | if (approvedActions.indexOf(req.params.resource) != -1) {
|
111 | joola.logger.debug('Approved action detected, bypassing token inspection.');
|
112 | return callback(null, true);
|
113 | }
|
114 |
|
115 | var token = req.headers['joola-token'];
|
116 | if (token == null || typeof(token) == 'undefined' || token == 'undefined')
|
117 | token = req.query.token;
|
118 |
|
119 | if (token || joola.config.auth.store == 'none')
|
120 | validate(token);
|
121 | else
|
122 | failed();
|
123 | };
|
124 |
|
125 | exports.validateAction = function (action, req, res, callback) {
|
126 | if (req.method == 'OPTIONS')
|
127 | return callback(null, true);
|
128 |
|
129 | var required = action.inputs.required;
|
130 | var optional = action.inputs.optional;
|
131 |
|
132 | var _params = [];
|
133 | _params.resource = req.params.resource;
|
134 | _params.action = req.params.action;
|
135 | _params.minres = req.params.minres;
|
136 |
|
137 | required.forEach(function (param) {
|
138 | if (!req.params[param])
|
139 | return callback(new ErrorTemplate('Required param [' + param + '] is missing.'), false);
|
140 | _params[param ] = req.params[param];
|
141 | });
|
142 |
|
143 | optional.forEach(function (param) {
|
144 | if (req.params[param])
|
145 | _params[param] = req.params[param];
|
146 | else
|
147 | _params[param] = '';
|
148 | });
|
149 |
|
150 | req.debug = {};
|
151 | Object.keys(_params).forEach(function (key) {
|
152 | req.debug[key] = _params[key];
|
153 | });
|
154 |
|
155 | req.params = _params;
|
156 |
|
157 | if (!req.user)
|
158 | return callback(new ErrorTemplate('Request for action by unauthenticated user.'), false);
|
159 |
|
160 | var userPermissions = [];
|
161 | req.user._roles.forEach(function (role) {
|
162 | joola.config.auth.roles.forEach(function (roleToCompareAgainst) {
|
163 | if (role === roleToCompareAgainst.id) {
|
164 | userPermissions = userPermissions.concat(roleToCompareAgainst.permissions);
|
165 | }
|
166 | });
|
167 | });
|
168 |
|
169 | if (util.isArray(action.permission))
|
170 | action.permission = action.permission[0];
|
171 | if (userPermissions.indexOf(action.permission) == -1)
|
172 | return callback(new ErrorTemplate('Missing permission to run this action.'), false);
|
173 |
|
174 | return callback(null, true);
|
175 | };
|
176 |
|
177 | exports.route = function (req, res) {
|
178 | var modulename = req.params.resource;
|
179 | var module;
|
180 | var action = req.params.action;
|
181 |
|
182 | _.extend(req.params, req.query);
|
183 |
|
184 | exports.validateToken(req, res, function (err, validated) {
|
185 | if (err)
|
186 | return exports.responseError(err, req, res);
|
187 | else if (!validated)
|
188 | return exports.responseError(new AuthErrorTemplate('Authentication failed.'), req, res);
|
189 |
|
190 | joola.logger.debug('Token verified ' + req.token);
|
191 |
|
192 | if (!modulename)
|
193 | return exports.responseError(new ErrorTemplate('Module not specified.'), req, res);
|
194 |
|
195 | try {
|
196 | module = require('./' + modulename);
|
197 | }
|
198 | catch (ex) {
|
199 | return exports.responseError(ex, req, res);
|
200 | }
|
201 |
|
202 | if (!action)
|
203 | action = 'index';
|
204 |
|
205 | try {
|
206 | action = module[action];
|
207 | exports.validateAction(action, req, res, function (err, validated) {
|
208 | if (err)
|
209 | return exports.responseError(err, req, res);
|
210 | else if (!validated)
|
211 | return exports.responseError(new ErrorTemplate('Failed to validate action.'), req, res);
|
212 | joola.logger.debug('Routing [' + action.name + ']...');
|
213 | return action.run(req, res);
|
214 | });
|
215 | }
|
216 | catch (ex) {
|
217 | console.log('err', ex);
|
218 | console.log(ex.stack);
|
219 | return exports.responseError(ex, req, res);
|
220 | }
|
221 | });
|
222 | }; |
\ | No newline at end of file |