1 | var path = require('path');
|
2 | var fs = require('fs');
|
3 | var os = require('os');
|
4 | var _util = require("util");
|
5 | var util = require("./util");
|
6 | var request = require("request");
|
7 | var http = require("http");
|
8 | var https = require("https");
|
9 | var async = require("async");
|
10 |
|
11 |
|
12 | var TRUSTED_PROFILE_CACHE = require("lru-cache")({
|
13 | max:100,
|
14 | maxAge: 1000 * 60 * 15
|
15 | });
|
16 |
|
17 |
|
18 | var USER_ENTRY_CACHE = require("lru-cache")({
|
19 | max: 100,
|
20 | maxAge: 1000 * 60 * 15
|
21 | });
|
22 |
|
23 | var authFilterLoggerEnabled = (process.env.CLOUDCMS_AUTH_FILTER_LOGGER_ENABLED === "true");
|
24 |
|
25 | exports = module.exports;
|
26 |
|
27 |
|
28 | var Gitana = require("gitana");
|
29 |
|
30 | var buildPassportCallback = exports.buildPassportCallback = function(providerConfig, provider)
|
31 | {
|
32 | return function(req, token, refreshToken, profile, done)
|
33 | {
|
34 | var info = {};
|
35 |
|
36 | info.providerId = providerConfig.id;
|
37 | info.providerUserId = provider.userIdentifier(profile);
|
38 | info.token = token;
|
39 | info.refreshToken = refreshToken;
|
40 |
|
41 | if (!info.providerUserId)
|
42 | {
|
43 | return done({
|
44 | "message": "Unable to determine provider user ID from profile"
|
45 | });
|
46 | }
|
47 |
|
48 | done(null, profile, info);
|
49 | };
|
50 | };
|
51 |
|
52 | var syncAttachment = exports.syncAttachment = function(gitanaUser, attachmentId, url, callback)
|
53 | {
|
54 | var baseURL = gitanaUser.getDriver().getOriginalConfiguration().baseURL;
|
55 | var authorizationHeader = gitanaUser.getDriver().getHttpHeaders()["Authorization"];
|
56 |
|
57 | var targetUrl = baseURL + gitanaUser.getUri() + "/attachments/" + attachmentId;
|
58 |
|
59 |
|
60 | var headers = {};
|
61 | headers["Authorization"] = authorizationHeader;
|
62 |
|
63 | request.get(url).pipe(request.post({
|
64 | url: targetUrl,
|
65 | headers: headers
|
66 | })).on("response", function(response) {
|
67 | callback();
|
68 | });
|
69 | };
|
70 |
|
71 | var _LOCK = function(lockIdentifiers, workFunction)
|
72 | {
|
73 | process.locks.lock(lockIdentifiers.join("_"), workFunction);
|
74 | };
|
75 |
|
76 | var logEvent = function(event, success, protocol, source, userId, ip, matchedGroup, userGroups, mandatoryGroups, accessGranted)
|
77 | {
|
78 | if (!authFilterLoggerEnabled)
|
79 | {
|
80 | return;
|
81 | }
|
82 |
|
83 | console.log(_util.format('%s|%s|%o|%s|%s|%s|%s|%s|%s|%s|%s|%s',
|
84 | event||"Authorization",
|
85 | event||"Authorization",
|
86 | new Date(),
|
87 | protocol||"https",
|
88 | success ? "Success" : "Failed",
|
89 | userId || "NA",
|
90 | ip || "NA",
|
91 | matchedGroup || "",
|
92 | (userGroups || ["NA"]).join(','),
|
93 | (mandatoryGroups || ["NA"]).join(','),
|
94 | accessGranted || "NA",
|
95 | os.hostname()
|
96 | ));
|
97 | };
|
98 |
|
99 |
|
100 |
|
101 | var impersonate = exports.impersonate = function(req, key, targetUser, callback)
|
102 | {
|
103 |
|
104 |
|
105 |
|
106 |
|
107 | var authInfo = req.gitana.getDriver().getAuthInfo();
|
108 | var currentUserId = authInfo.principalDomainId + "/" + authInfo.principalId;
|
109 |
|
110 | var grantImpersonator = function(done)
|
111 | {
|
112 | Chain(targetUser).trap(function(e) {
|
113 | done();
|
114 | return false;
|
115 | }).grantAuthority(currentUserId, "impersonator").then(function () {
|
116 | done();
|
117 | });
|
118 | };
|
119 |
|
120 | var revokeImpersonator = function(done)
|
121 | {
|
122 | Chain(targetUser).trap(function(e) {
|
123 | done();
|
124 | return false;
|
125 | }).revokeAuthority(currentUserId, "impersonator").then(function () {
|
126 | done();
|
127 | });
|
128 | };
|
129 |
|
130 | var connectImpersonator = function(done)
|
131 | {
|
132 | var headers = {};
|
133 | headers["Authorization"] = req.gitana.platform().getDriver().getHttpHeaders()["Authorization"];
|
134 |
|
135 | var agent = util.getAgent(req.gitanaConfig.baseURL);
|
136 |
|
137 | request({
|
138 | "method": "POST",
|
139 | "url": req.gitanaConfig.baseURL + "/auth/impersonate/" + targetUser.getDomainId() + "/" + targetUser.getId(),
|
140 | "qs": {},
|
141 | "json": {},
|
142 | "headers": headers,
|
143 | "agent": agent,
|
144 | "timeout": process.defaultHttpTimeoutMs
|
145 | }, function(err, response, json) {
|
146 |
|
147 |
|
148 | var x = {
|
149 | "clientKey": req.gitanaConfig.clientKey,
|
150 | "clientSecret": req.gitanaConfig.clientSecret,
|
151 | "ticket": json.ticket,
|
152 | "baseURL": req.gitanaConfig.baseURL,
|
153 | "key": key
|
154 | };
|
155 | if (req.gitanaConfig.application) {
|
156 | x.application = req.gitanaConfig.application;
|
157 | x.appCacheKey = key;
|
158 | }
|
159 | Gitana.connect(x, function (err) {
|
160 |
|
161 | if (err)
|
162 | {
|
163 | console.log("Failed to connect to Cloud CMS: " + JSON.stringify(err));
|
164 | return done(err);
|
165 | }
|
166 |
|
167 | var platform = this;
|
168 | var appHelper = null;
|
169 | if (x.application) {
|
170 | appHelper = this;
|
171 | platform = this.platform();
|
172 | }
|
173 |
|
174 | done(null, platform, appHelper, key);
|
175 | });
|
176 | });
|
177 | };
|
178 |
|
179 | grantImpersonator(function(err) {
|
180 |
|
181 | if (err) {
|
182 | return revokeImpersonator(function() {
|
183 | callback(err);
|
184 | });
|
185 | }
|
186 |
|
187 | connectImpersonator(function(err, platform, appHelper, key) {
|
188 |
|
189 | if (err) {
|
190 | return revokeImpersonator(function() {
|
191 | callback(err);
|
192 | });
|
193 | }
|
194 |
|
195 | revokeImpersonator(function(err) {
|
196 |
|
197 | if (err) {
|
198 | return callback(err);
|
199 | }
|
200 |
|
201 | callback(null, platform, appHelper, key);
|
202 | });
|
203 | });
|
204 | });
|
205 | };
|
206 |
|
207 | var readTrustedProfile = exports.readTrustedProfile = function(identifier)
|
208 | {
|
209 | return TRUSTED_PROFILE_CACHE.get(identifier);
|
210 | };
|
211 |
|
212 | var writeTrustedProfile = exports.writeTrustedProfile = function(identifier, profile)
|
213 | {
|
214 | TRUSTED_PROFILE_CACHE.set(identifier, profile);
|
215 | };
|
216 |
|
217 | var removeTrustedProfile = exports.removeTrustedProfile = function(identifier)
|
218 | {
|
219 | TRUSTED_PROFILE_CACHE.del(identifier);
|
220 | };
|
221 |
|
222 | var readUserCacheEntry = exports.readUserCacheEntry = function(identifier)
|
223 | {
|
224 | return USER_ENTRY_CACHE.get(identifier);
|
225 | };
|
226 |
|
227 | var writeUserCacheEntry = exports.writeUserCacheEntry = function(identifier, entry)
|
228 | {
|
229 | USER_ENTRY_CACHE.set(identifier, entry);
|
230 | };
|
231 |
|
232 | var removeUserCacheEntry = exports.removeUserCacheEntry = function(identifier)
|
233 | {
|
234 | USER_ENTRY_CACHE.del(identifier);
|
235 | };
|
236 |
|
237 |
|
238 | var syncProfile = exports.syncProfile = function(req, res, strategy, domain, providerId, provider, profile, token, refreshToken, callback) {
|
239 |
|
240 | return provider.parseProfile(req, profile, function(err, userObject, groupsArray, mandatoryGroupsArray) {
|
241 |
|
242 |
|
243 | if (mandatoryGroupsArray && mandatoryGroupsArray.length > 0)
|
244 | {
|
245 |
|
246 | for (var i = 0; i < mandatoryGroupsArray.length; i++)
|
247 | {
|
248 | mandatoryGroupsArray[i] = mandatoryGroupsArray[i].trim();
|
249 | }
|
250 |
|
251 |
|
252 | var hasMandatoryGroup = false;
|
253 | var mandatoryGroupsMap = {};
|
254 | var matchedGroup = null;
|
255 | for (var i = 0; i < mandatoryGroupsArray.length; i++) {
|
256 | mandatoryGroupsMap[mandatoryGroupsArray[i]] = true;
|
257 | }
|
258 | for (var i = 0; i < groupsArray.length; i++) {
|
259 | if (mandatoryGroupsMap[groupsArray[i]]) {
|
260 | matchedGroup = groupsArray[i];
|
261 | hasMandatoryGroup = true;
|
262 | }
|
263 | }
|
264 | if (!hasMandatoryGroup)
|
265 | {
|
266 | logEvent("Authorization", false, req.protocol, providerId, profile.nameID, req.ip, null, groupsArray, mandatoryGroupsArray, null);
|
267 | return callback({
|
268 | "message": "The incoming user does not belong to one of the mandatory groups",
|
269 | "noMandatoryGroup": true
|
270 | });
|
271 | }
|
272 | else{
|
273 | if (domain && domain._doc) {
|
274 | logEvent("Authorization", true, req.protocol, providerId, profile.nameID, req.ip, matchedGroup, groupsArray, mandatoryGroupsArray, "AddToDomain:" + domain._doc);
|
275 | } else {
|
276 | logEvent("Authorization", true, req.protocol, providerId, profile.nameID, req.ip, matchedGroup, groupsArray, mandatoryGroupsArray, "AddToDomain");
|
277 | }
|
278 | }
|
279 | }
|
280 | else
|
281 | {
|
282 | if (domain && domain._doc) {
|
283 | logEvent("Authorization", true, req.protocol, providerId, profile.nameID, req.ip, null, groupsArray, null, "AddToDomain:" + domain._doc);
|
284 | } else {
|
285 | logEvent("Authorization", true, req.protocol, providerId, profile.nameID, req.ip, null, groupsArray, null, "AddToDomain");
|
286 | }
|
287 | }
|
288 |
|
289 | req.application(function(err, application) {
|
290 |
|
291 |
|
292 | req.applicationSettings(function(err, settings) {
|
293 |
|
294 | if (err || !settings) {
|
295 | settings = {};
|
296 | }
|
297 |
|
298 | var providerUserId = provider.userIdentifier(profile);
|
299 | if (!providerUserId)
|
300 | {
|
301 | return callback({
|
302 | "message": "Unable to determine provider user ID from profile"
|
303 | });
|
304 | }
|
305 |
|
306 | var key = token;
|
307 |
|
308 |
|
309 | var CACHE_IDENTIFIER = providerId + "/" + providerUserId;
|
310 |
|
311 | var entry = readUserCacheEntry(CACHE_IDENTIFIER);
|
312 | if (entry)
|
313 | {
|
314 | var gitanaUser = entry.gitanaUser;
|
315 | var platform = entry.platform;
|
316 | var appHelper = entry.appHelper;
|
317 | var key = entry.key;
|
318 |
|
319 | if (gitanaUser && platform && key)
|
320 | {
|
321 |
|
322 | return callback(null, gitanaUser, platform, appHelper, key, platform.getDriver());
|
323 | }
|
324 | else
|
325 | {
|
326 |
|
327 | removeUserCacheEntry(CACHE_IDENTIFIER);
|
328 | }
|
329 | }
|
330 |
|
331 | _LOCK([CACHE_IDENTIFIER], function(releaseLockFn) {
|
332 | _handleSyncUser(req, strategy, settings, key, domain, providerId, providerUserId, token, refreshToken, userObject, groupsArray, function (err, gitanaUser) {
|
333 |
|
334 | if (err) {
|
335 | releaseLockFn();
|
336 | return callback(err);
|
337 | }
|
338 |
|
339 |
|
340 | if (!gitanaUser) {
|
341 | releaseLockFn();
|
342 | return callback();
|
343 | }
|
344 |
|
345 | _handleConnectAsUser(req, key, gitanaUser, function (err, platform, appHelper, key) {
|
346 |
|
347 | if (err) {
|
348 | releaseLockFn();
|
349 | return callback(err);
|
350 | }
|
351 |
|
352 |
|
353 | writeUserCacheEntry(CACHE_IDENTIFIER, {
|
354 | "gitanaUser": gitanaUser,
|
355 | "platform": platform,
|
356 | "appHelper": appHelper,
|
357 | "key": key
|
358 | });
|
359 |
|
360 | releaseLockFn();
|
361 |
|
362 | callback(err, gitanaUser, platform, appHelper, key, platform.getDriver());
|
363 | }, gitanaUser);
|
364 | });
|
365 | });
|
366 | });
|
367 | });
|
368 | });
|
369 | };
|
370 |
|
371 | var _handleConnectAsUser = function(req, key, gitanaUser, callback) {
|
372 |
|
373 | var appHelper = Gitana.APPS[key];
|
374 | if (appHelper)
|
375 | {
|
376 |
|
377 | return callback(null, appHelper.platform(), appHelper, key);
|
378 | }
|
379 |
|
380 | var platform = Gitana.PLATFORM_CACHE(key);
|
381 | if (platform)
|
382 | {
|
383 |
|
384 | return callback(null, platform, null, key);
|
385 | }
|
386 |
|
387 | impersonate(req, key, gitanaUser, function(err, platform, appHelper, key) {
|
388 | callback(err, platform, appHelper, key);
|
389 | });
|
390 | };
|
391 |
|
392 | var _handleSyncUser = function(req, strategy, settings, key, domain, providerId, providerUserId, token, refreshToken, userObject, groupsArray, callback) {
|
393 |
|
394 | __handleSyncUser(req, strategy, settings, key, domain, providerId, providerUserId, token, refreshToken, userObject, function(err, gitanaUser, synced) {
|
395 |
|
396 | if (err) {
|
397 | return callback(err);
|
398 | }
|
399 |
|
400 | if (!gitanaUser)
|
401 | {
|
402 | if (!strategy.autoRegister)
|
403 | {
|
404 | console.log("Sync user did not find a user for providerUserId: " + providerUserId + " but autoRegister is turned off, cannot auto-create the user");
|
405 |
|
406 | return callback({
|
407 | "message": "User not found (autoRegister is disabled, cannot auto-create)",
|
408 | "noAutoRegister": true
|
409 | });
|
410 | }
|
411 |
|
412 | console.log("Sync user did not produce a user object");
|
413 |
|
414 | return callback({
|
415 | "message": "User not found"
|
416 | });
|
417 | }
|
418 |
|
419 | if (!synced)
|
420 | {
|
421 | return callback(null, gitanaUser);
|
422 | }
|
423 |
|
424 |
|
425 | __handleSyncGroups(req, strategy, settings, gitanaUser, groupsArray, function(err, gitanaUser) {
|
426 |
|
427 | return callback(null, gitanaUser);
|
428 |
|
429 | });
|
430 | });
|
431 |
|
432 | };
|
433 |
|
434 | var __handleSyncUser = function(req, strategy, settings, key, domain, providerId, providerUserId, token, refreshToken, userObject, callback) {
|
435 |
|
436 | var baseURL = req.gitanaConfig.baseURL;
|
437 | var authorizationHeader = req.gitana.getDriver().getHttpHeaders()["Authorization"];
|
438 | var targetUrl = baseURL + domain.getUri() + "/connections/sync";
|
439 |
|
440 |
|
441 | var headers = {};
|
442 | headers["Authorization"] = authorizationHeader;
|
443 |
|
444 | var agent = util.getAgent(req.gitanaConfig.baseURL);
|
445 |
|
446 | if (!userObject) {
|
447 | userObject = {};
|
448 | }
|
449 |
|
450 | var connectionObject = {};
|
451 | connectionObject.accessToken = token;
|
452 | connectionObject.refreshToken = refreshToken;
|
453 |
|
454 | var json = {
|
455 | "user": userObject,
|
456 | "connection": connectionObject
|
457 | };
|
458 |
|
459 | var autoCreate = strategy.autoRegister ? true : false;
|
460 |
|
461 | var requestConfig = {
|
462 | "method": "POST",
|
463 | "url": targetUrl,
|
464 | "qs": {
|
465 | "providerId": providerId,
|
466 | "providerUserId": providerUserId,
|
467 | "autoCreate": autoCreate
|
468 | },
|
469 | "json": json,
|
470 | "headers": headers,
|
471 | "agent": agent,
|
472 | "timeout": process.defaultHttpTimeoutMs
|
473 | };
|
474 |
|
475 | request(requestConfig, function(err, response, json) {
|
476 |
|
477 | if (err) {
|
478 | return callback(err);
|
479 | }
|
480 |
|
481 | if (json.error === "invalid_token")
|
482 | {
|
483 |
|
484 | return req.gitana.getDriver().reloadAuthInfo(function () {
|
485 | __handleSyncUser(req, strategy, settings, key, domain, providerId, providerUserId, token, refreshToken, userObject, function(err, gitanaUser, synced) {
|
486 | callback(err, gitanaUser, synced);
|
487 | })
|
488 | });
|
489 | }
|
490 |
|
491 | if (!json.user) {
|
492 | console.log("Did not see json.user, JSON is: " + JSON.stringify(json, null, 2));
|
493 | return callback({
|
494 | "message": "Missing json.user"
|
495 | });
|
496 | }
|
497 |
|
498 | var userId = json.user._doc;
|
499 | var domainId = json.user.domainId;
|
500 | var synced = json.user.synced;
|
501 |
|
502 |
|
503 | Chain(domain).readPrincipal(userId).then(function() {
|
504 | callback(null, this, synced);
|
505 | });
|
506 |
|
507 | });
|
508 | };
|
509 |
|
510 | var executeRule = function(req, rule, gitanaUser, callback)
|
511 | {
|
512 |
|
513 |
|
514 |
|
515 |
|
516 |
|
517 |
|
518 |
|
519 |
|
520 |
|
521 | var ensureArray = function(teamIdentifiers) {
|
522 | var array = [];
|
523 | if (!teamIdentifiers) {
|
524 | return array;
|
525 | }
|
526 |
|
527 | if (typeof(teamIdentifiers) === "string") {
|
528 | array.push(teamIdentifiers);
|
529 | }
|
530 |
|
531 | for (var i = 0; i < teamIdentifiers.length; i++) {
|
532 | array.push(teamIdentifiers[i]);
|
533 | }
|
534 |
|
535 | return array;
|
536 | };
|
537 |
|
538 | var addToProject = function(projectId, teamIdentifiers, finished) {
|
539 |
|
540 | if (!teamIdentifiers) {
|
541 | teamIdentifiers = "project-users-team";
|
542 | }
|
543 |
|
544 | teamIdentifiers = ensureArray(teamIdentifiers);
|
545 |
|
546 | var project = null;
|
547 | var stack = null;
|
548 |
|
549 | return req.gitana.platform().trap(function(e) {
|
550 | return false;
|
551 | }).readProject(projectId).then(function(){
|
552 | project = this;
|
553 | }).readStack().then(function() {
|
554 | stack = this;
|
555 |
|
556 | var fns = [];
|
557 | for (var i = 0; i < teamIdentifiers.length; i++)
|
558 | {
|
559 | var fn = function(stack, teamIdentifier, user) {
|
560 | return function(d) {
|
561 |
|
562 | console.log("Working on stack: " + stack._doc + ", team: " + teamIdentifier + ", user: " + user._doc);
|
563 |
|
564 | Chain(stack).trap(function(e) {
|
565 | d();
|
566 | return false;
|
567 | }).readTeam(teamIdentifier).then(function() {
|
568 | var team = this;
|
569 |
|
570 | Chain(team).hasMember(user, function(has) {
|
571 | if (has) {
|
572 | return d();
|
573 | }
|
574 | Chain(team).addMember(user).then(function() {
|
575 | d();
|
576 | });
|
577 | });
|
578 | });
|
579 |
|
580 | }
|
581 | }(stack, teamIdentifiers[i], gitanaUser);
|
582 | fns.push(fn);
|
583 | }
|
584 | async.series(fns, function() {
|
585 | finished();
|
586 | });
|
587 | });
|
588 | };
|
589 |
|
590 | var addToPlatformTeams = function(teamIdentifiers, finished) {
|
591 |
|
592 | if (!teamIdentifiers) {
|
593 | teamIdentifiers = "project-users-team";
|
594 | }
|
595 |
|
596 | teamIdentifiers = ensureArray(teamIdentifiers);
|
597 |
|
598 | var platform = null;
|
599 |
|
600 | return Chain(req.gitana.platform()).trap(function(e) {
|
601 | return false;
|
602 | }).then(function() {
|
603 | platform = this;
|
604 |
|
605 | var fns = [];
|
606 | for (var i = 0; i < teamIdentifiers.length; i++)
|
607 | {
|
608 | var fn = function(platform, teamIdentifier, user) {
|
609 | return function(d) {
|
610 |
|
611 | console.log("Working on platform team: " + teamIdentifier + ", user: " + user._doc);
|
612 |
|
613 | Chain(platform).trap(function(e) {
|
614 | d();
|
615 | return false;
|
616 | }).readTeam(teamIdentifier).then(function() {
|
617 | var team = this;
|
618 |
|
619 | Chain(team).hasMember(user, function(has) {
|
620 | if (has) {
|
621 | return d();
|
622 | }
|
623 | Chain(team).addMember(user).then(function() {
|
624 | d();
|
625 | });
|
626 | });
|
627 | });
|
628 |
|
629 | }
|
630 | }(platform, teamIdentifiers[i], gitanaUser);
|
631 | fns.push(fn);
|
632 | }
|
633 | async.series(fns, function() {
|
634 | finished();
|
635 | });
|
636 | });
|
637 | };
|
638 |
|
639 | const {VM} = require("vm2");
|
640 | var vm = new VM({
|
641 | timeout: 5000,
|
642 | sandbox: {
|
643 | "addToProject": function(projectId, teamIdentifiers) {
|
644 | return addToProject(projectId, teamIdentifiers, function() {
|
645 | console.log("Added user: " + gitanaUser._doc + " to project: " + projectId + ", teams: " + JSON.stringify(teamIdentifiers));
|
646 | });
|
647 | },
|
648 | "addToPlatformTeam": function(teamIdentifier) {
|
649 | return addToPlatformTeams([teamIdentifier], function() {
|
650 | console.log("Added user: " + gitanaUser._doc + " to platform team: " + teamIdentifier);
|
651 | });
|
652 | },
|
653 | "addToPlatformTeams": function(teamIdentifiers) {
|
654 | return addToPlatformTeams(teamIdentifiers, function() {
|
655 | console.log("Added user: " + gitanaUser._doc + " to platform teams: " + JSON.stringify(teamIdentifiers));
|
656 | });
|
657 | }
|
658 | }
|
659 | });
|
660 | vm.run(rule);
|
661 |
|
662 | setTimeout(function() {
|
663 | callback();
|
664 | }, 250);
|
665 | };
|
666 |
|
667 | var __handleSyncGroups = function(req, strategy, settings, gitanaUser, groupsArray, callback) {
|
668 |
|
669 | if (!groupsArray || groupsArray.length === 0)
|
670 | {
|
671 | return callback(null, gitanaUser);
|
672 | }
|
673 |
|
674 |
|
675 | if (!settings || !settings.sso || !settings.sso.groupMappings || settings.sso.groupMappings.length === 0) {
|
676 | return callback(null, gitanaUser);
|
677 | }
|
678 |
|
679 |
|
680 | var groupRules = {};
|
681 | for (var i = 0; i < settings.sso.groupMappings.length; i++)
|
682 | {
|
683 | groupRules[settings.sso.groupMappings[i].key] = settings.sso.groupMappings[i].values;
|
684 | }
|
685 |
|
686 | var fns = [];
|
687 | for (var i = 0; i < groupsArray.length; i++)
|
688 | {
|
689 | var groupIdentifier = groupsArray[i];
|
690 |
|
691 | var rules = groupRules[groupIdentifier];
|
692 | if (rules)
|
693 | {
|
694 | for (var x = 0; x < rules.length; x++)
|
695 | {
|
696 | var fn = function (rule, gitanaUser) {
|
697 | return function (done) {
|
698 | executeRule(req, rule, gitanaUser, function (err) {
|
699 | done(err);
|
700 | });
|
701 | }
|
702 | }(rules[x], gitanaUser);
|
703 | fns.push(fn);
|
704 | }
|
705 | }
|
706 | }
|
707 |
|
708 | async.series(fns, function() {
|
709 | callback(null, gitanaUser);
|
710 | });
|
711 | };
|