1 | /* jshint node: true */
|
2 | ;
|
3 |
|
4 | /**
|
5 | * get session secret from db
|
6 | * acl: check if req route is allowed as express middelware
|
7 | * decrypt token an put rights object in req
|
8 | */
|
9 |
|
10 |
|
11 | var jwt = require('jsonwebtoken'),
|
12 | NodeCache = require("node-cache"),
|
13 | myCache = new NodeCache({
|
14 | stdTTL: 1000,
|
15 | checkperiod: 250
|
16 | }),
|
17 | os = require('os'),
|
18 | config = require("rf-config"),
|
19 | log = require("rf-log"),
|
20 | db = require("rf-load").require("db").db,
|
21 | app = require("rf-load").require("http").app;
|
22 |
|
23 |
|
24 |
|
25 | // get internal ip addresses for allowing internal requests
|
26 | var interfaces = os.networkInterfaces();
|
27 | var internal_ip_addresses = [];
|
28 | for (var k in interfaces) {
|
29 | for (var k2 in interfaces[k]) {
|
30 | var address = interfaces[k][k2];
|
31 | internal_ip_addresses.push(address.address.replace("::ffff:", ""));
|
32 | }
|
33 | }
|
34 |
|
35 |
|
36 | module.exports.start = function(options, startNextModule) {
|
37 |
|
38 | //get session secret from db
|
39 | db.global.settings.findOne({
|
40 | name: "sessionSecret"
|
41 | }, function(err, doc) {
|
42 | var sessionSecret;
|
43 | if (doc && doc.settings && doc.settings.value) {
|
44 | sessionSecret = doc.settings.value;
|
45 | } else {
|
46 | // no secret => create one and put it in db (avalibale for other apps)
|
47 | log.info("Couldn't load session secret, creating a new one");
|
48 | sessionSecret = require('crypto').randomBytes(64).toString('hex');
|
49 |
|
50 | db.global.mongooseConnection.collection("settings").insert({
|
51 | name: "sessionSecret",
|
52 | settings: {
|
53 | value: sessionSecret
|
54 | }
|
55 | });
|
56 | }
|
57 | config.sessionSecret = sessionSecret; // login function als needs it
|
58 | startACL(sessionSecret);
|
59 | });
|
60 |
|
61 |
|
62 | function startACL(sessionSecret) {
|
63 |
|
64 |
|
65 | // process the token
|
66 | app.use(function(req, res, next) {
|
67 |
|
68 | // check for token
|
69 | var token = req.body.token || req.query.token || req.headers['x-access-token'];
|
70 |
|
71 | if (token) {
|
72 | try {
|
73 | getSession(token, res, function(session) {
|
74 | // make data accessible afterwards
|
75 | req._session = session;
|
76 | req._token = token;
|
77 | // req._decoded = jwt.verify(token, sessionSecret, {
|
78 | // ignoreExpiration: true
|
79 | // });
|
80 | next();
|
81 | });
|
82 | } catch (err) {
|
83 | error();
|
84 | }
|
85 |
|
86 | // no token
|
87 | } else {
|
88 | next();
|
89 | }
|
90 |
|
91 | function error () {
|
92 | res.status(403).send('AuthenticateFailed');
|
93 | }
|
94 |
|
95 |
|
96 | function getSession(token, res, next) {
|
97 |
|
98 | // session with key "token" in cach?
|
99 | myCache.get(token, function(err, session) {
|
100 |
|
101 | if (err) {
|
102 | log.error("node-cache ", err);
|
103 | } else {
|
104 | // not in cache => get from db and put in cache
|
105 | if (session === undefined || session === null) {
|
106 | db.user.sessions.findOne({
|
107 | "token": token
|
108 | })
|
109 | .populate({
|
110 | path: 'user',
|
111 | populate: {
|
112 | path: 'account'
|
113 | }
|
114 | })
|
115 | .exec(function(err, doc) {
|
116 |
|
117 | if (doc) {
|
118 | session = doc;
|
119 | myCache.set(token, session, function(err, success) {
|
120 | if (err) {
|
121 | log.error("node-cache ", err);
|
122 | } else {
|
123 | //console.log("session from db", session);
|
124 | next(session);
|
125 | }
|
126 | });
|
127 |
|
128 | // no session found in db
|
129 | } else {
|
130 | error();
|
131 | }
|
132 |
|
133 | });
|
134 |
|
135 | // return session from cache
|
136 | } else {
|
137 | // console.log("session in cache", session);
|
138 | next(session);
|
139 | }
|
140 | }
|
141 | });
|
142 |
|
143 | }
|
144 | });
|
145 |
|
146 |
|
147 | // check if rout allowed
|
148 | app.use(function(req, res, next) {
|
149 |
|
150 | //Do not protect internal requests
|
151 | var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
152 | ip = ip.replace("::ffff:", "");
|
153 |
|
154 | // console.log(req._session);
|
155 |
|
156 | if (internal_ip_addresses.indexOf(ip) < 0) {
|
157 |
|
158 | if (!config.acl) {
|
159 | log.warning("No acls found in config! Nothing is protected!");
|
160 | next();
|
161 | } else {
|
162 | for (var c in config.acl) {
|
163 |
|
164 | if (req.url.match(new RegExp(c, 'g'))) {
|
165 |
|
166 | //protected
|
167 | if (config.acl[c] !== false) {
|
168 |
|
169 |
|
170 | //req._session
|
171 | // req._token
|
172 |
|
173 | // TODO
|
174 | //Check for roles for this route
|
175 | // if (decoded.roles.indexOf(config.acl[c]) < 0) {
|
176 | // return res.status(403).json({
|
177 | // success: false,
|
178 | // message: 'Wrong permissions.'
|
179 | // }, 403);
|
180 | // }
|
181 |
|
182 | // everything good
|
183 | next();
|
184 | } else { // no token => error
|
185 |
|
186 | next();
|
187 |
|
188 | // return res.status(403).json({
|
189 | // success: false,
|
190 | // message: 'No token provided.'
|
191 | // }, 403);
|
192 | }
|
193 |
|
194 | //unprotected
|
195 | } else {
|
196 | next();
|
197 | }
|
198 | }
|
199 | }
|
200 | // internal
|
201 | }else {
|
202 | next();
|
203 | }
|
204 |
|
205 | });
|
206 |
|
207 |
|
208 | // provide the login url (no acl here)
|
209 | app.post('/basic-config', function(req, res) {
|
210 | var loginUrls = config.global.apps.login.urls;
|
211 | var basicInfo = {
|
212 | app: config.app,
|
213 | loginUrl: loginUrls.main + loginUrls.login,
|
214 | loginMainUrl: loginUrls.main,
|
215 | };
|
216 | res.status(200).send(basicInfo).end();
|
217 | });
|
218 |
|
219 |
|
220 | log.success("Session started");
|
221 | startNextModule();
|
222 |
|
223 | }
|
224 |
|
225 |
|
226 |
|
227 |
|
228 | };
|