aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--frontend/js/app.js57
-rw-r--r--npm-shrinkwrap.json15
-rw-r--r--package.json4
-rwxr-xr-xserver.js3
-rw-r--r--src/auth.js65
5 files changed, 112 insertions, 32 deletions
diff --git a/frontend/js/app.js b/frontend/js/app.js
index 33346aa..b07560a 100644
--- a/frontend/js/app.js
+++ b/frontend/js/app.js
@@ -1,37 +1,54 @@
1(function () { 1(function () {
2'use strict'; 2'use strict';
3 3
4function getProfile(accessToken, callback) {
5 callback = callback || function (error) { if (error) console.error(error); };
6
7 superagent.get('/api/profile').query({ access_token: accessToken }).end(function (error, result) {
8 app.busy = false;
9
10 if (error && !error.response) return callback(error);
11 if (result.statusCode !== 200) {
12 delete localStorage.accessToken;
13 return callback('Invalid access token');
14 }
15
16 localStorage.accessToken = accessToken;
17 app.session.username = result.body.username;
18 app.session.valid = true;
19
20 callback();
21 });
22}
23
4function login(username, password) { 24function login(username, password) {
5 username = username || app.loginData.username; 25 username = username || app.loginData.username;
6 password = password || app.loginData.password; 26 password = password || app.loginData.password;
7 27
8 app.busy = true; 28 app.busy = true;
9 29
10 superagent.get('/api/files/').query({ username: username, password: password }).end(function (error, result) { 30 superagent.post('/api/login').query({ username: username, password: password }).end(function (error, result) {
11 app.busy = false; 31 app.busy = false;
12 32
13 if (error) return console.error(error); 33 if (error) return console.error(error);
14 if (result.statusCode === 401) return console.error('Invalid credentials'); 34 if (result.statusCode === 401) return console.error('Invalid credentials');
15 35
16 app.session.valid = true; 36 getProfile(result.body.accessToken, function (error) {
17 app.session.username = username; 37 if (error) return console.error(error);
18 app.session.password = password;
19
20 // clearly not the best option
21 localStorage.username = username;
22 localStorage.password = password;
23 38
24 loadDirectory(window.location.hash.slice(1)); 39 loadDirectory(window.location.hash.slice(1));
40 });
25 }); 41 });
26} 42}
27 43
28function logout() { 44function logout() {
29 app.session.valid = false; 45 superagent.post('/api/logout').query({ access_token: localStorage.accessToken }).end(function (error) {
30 app.session.username = null; 46 if (error) console.error(error);
31 app.session.password = null; 47
48 app.session.valid = false;
32 49
33 delete localStorage.username; 50 delete localStorage.accessToken;
34 delete localStorage.password; 51 });
35} 52}
36 53
37function sanitize(filePath) { 54function sanitize(filePath) {
@@ -77,7 +94,7 @@ function loadDirectory(filePath) {
77 94
78 filePath = filePath ? sanitize(filePath) : '/'; 95 filePath = filePath ? sanitize(filePath) : '/';
79 96
80 superagent.get('/api/files/' + encode(filePath)).query({ username: app.session.username, password: app.session.password }).end(function (error, result) { 97 superagent.get('/api/files/' + encode(filePath)).query({ access_token: localStorage.accessToken }).end(function (error, result) {
81 app.busy = false; 98 app.busy = false;
82 99
83 if (result && result.statusCode === 401) return logout(); 100 if (result && result.statusCode === 401) return logout();
@@ -138,7 +155,7 @@ function uploadFiles(files) {
138 var formData = new FormData(); 155 var formData = new FormData();
139 formData.append('file', file); 156 formData.append('file', file);
140 157
141 superagent.post('/api/files' + path).query({ username: app.session.username, password: app.session.password }).send(formData).end(function (error, result) { 158 superagent.post('/api/files' + path).query({ access_token: localStorage.accessToken }).send(formData).end(function (error, result) {
142 if (result && result.statusCode === 401) return logout(); 159 if (result && result.statusCode === 401) return logout();
143 if (result && result.statusCode !== 201) console.error('Error uploading file: ', result.statusCode); 160 if (result && result.statusCode !== 201) console.error('Error uploading file: ', result.statusCode);
144 if (error) console.error(error); 161 if (error) console.error(error);
@@ -189,7 +206,7 @@ function del(entry) {
189 206
190 var path = encode(sanitize(app.path + '/' + entry.filePath)); 207 var path = encode(sanitize(app.path + '/' + entry.filePath));
191 208
192 superagent.del('/api/files' + path).query({ username: app.session.username, password: app.session.password, recursive: true }).end(function (error, result) { 209 superagent.del('/api/files' + path).query({ access_token: localStorage.accessToken, recursive: true }).end(function (error, result) {
193 app.busy = false; 210 app.busy = false;
194 211
195 if (result && result.statusCode === 401) return logout(); 212 if (result && result.statusCode === 401) return logout();
@@ -216,7 +233,7 @@ function rename(data) {
216 var path = encode(sanitize(app.path + '/' + data.entry.filePath)); 233 var path = encode(sanitize(app.path + '/' + data.entry.filePath));
217 var newFilePath = sanitize(app.path + '/' + data.newFilePath); 234 var newFilePath = sanitize(app.path + '/' + data.newFilePath);
218 235
219 superagent.put('/api/files' + path).query({ username: app.session.username, password: app.session.password }).send({ newFilePath: newFilePath }).end(function (error, result) { 236 superagent.put('/api/files' + path).query({ access_token: localStorage.accessToken }).send({ newFilePath: newFilePath }).end(function (error, result) {
220 app.busy = false; 237 app.busy = false;
221 238
222 if (result && result.statusCode === 401) return logout(); 239 if (result && result.statusCode === 401) return logout();
@@ -241,7 +258,7 @@ function createDirectory(name) {
241 258
242 var path = encode(sanitize(app.path + '/' + name)); 259 var path = encode(sanitize(app.path + '/' + name));
243 260
244 superagent.post('/api/files' + path).query({ username: app.session.username, password: app.session.password, directory: true }).end(function (error, result) { 261 superagent.post('/api/files' + path).query({ access_token: localStorage.accessToken, directory: true }).end(function (error, result) {
245 app.busy = false; 262 app.busy = false;
246 263
247 if (result && result.statusCode === 401) return logout(); 264 if (result && result.statusCode === 401) return logout();
@@ -327,7 +344,7 @@ var app = new Vue({
327 344
328window.app = app; 345window.app = app;
329 346
330login(localStorage.username, localStorage.password); 347getProfile(localStorage.accessToken);
331 348
332$(window).on('hashchange', function () { 349$(window).on('hashchange', function () {
333 loadDirectory(window.location.hash.slice(1)); 350 loadDirectory(window.location.hash.slice(1));
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 6d34f16..ff96bbb 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -903,6 +903,11 @@
903 } 903 }
904 } 904 }
905 }, 905 },
906 "passport-http-bearer": {
907 "version": "1.0.1",
908 "from": "passport-http-bearer@latest",
909 "resolved": "https://registry.npmjs.org/passport-http-bearer/-/passport-http-bearer-1.0.1.tgz"
910 },
906 "passport-ldapjs": { 911 "passport-ldapjs": {
907 "version": "1.0.2", 912 "version": "1.0.2",
908 "from": "passport-ldapjs@>=1.0.2 <2.0.0", 913 "from": "passport-ldapjs@>=1.0.2 <2.0.0",
@@ -1016,6 +1021,11 @@
1016 } 1021 }
1017 } 1022 }
1018 }, 1023 },
1024 "passport-strategy": {
1025 "version": "1.0.0",
1026 "from": "passport-strategy@>=1.0.0 <2.0.0",
1027 "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz"
1028 },
1019 "readline-sync": { 1029 "readline-sync": {
1020 "version": "1.4.1", 1030 "version": "1.4.1",
1021 "from": "readline-sync@>=1.4.1 <2.0.0", 1031 "from": "readline-sync@>=1.4.1 <2.0.0",
@@ -1534,6 +1544,11 @@
1534 "version": "1.8.3", 1544 "version": "1.8.3",
1535 "from": "underscore@>=1.8.3 <2.0.0", 1545 "from": "underscore@>=1.8.3 <2.0.0",
1536 "resolved": "http://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz" 1546 "resolved": "http://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz"
1547 },
1548 "uuid": {
1549 "version": "3.0.1",
1550 "from": "uuid@latest",
1551 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz"
1537 } 1552 }
1538 } 1553 }
1539} 1554}
diff --git a/package.json b/package.json
index 55bfd4b..e2e0488 100644
--- a/package.json
+++ b/package.json
@@ -37,13 +37,15 @@
37 "morgan": "^1.7.0", 37 "morgan": "^1.7.0",
38 "multiparty": "^4.1.2", 38 "multiparty": "^4.1.2",
39 "passport": "^0.2.2", 39 "passport": "^0.2.2",
40 "passport-http-bearer": "^1.0.1",
40 "passport-ldapjs": "^1.0.2", 41 "passport-ldapjs": "^1.0.2",
41 "readline-sync": "^1.4.1", 42 "readline-sync": "^1.4.1",
42 "request": "^2.69.0", 43 "request": "^2.69.0",
43 "safetydance": "^0.1.1", 44 "safetydance": "^0.1.1",
44 "serve-index": "^1.8.0", 45 "serve-index": "^1.8.0",
45 "superagent": "^1.7.2", 46 "superagent": "^1.7.2",
46 "underscore": "^1.8.3" 47 "underscore": "^1.8.3",
48 "uuid": "^3.0.1"
47 }, 49 },
48 "devDependencies": { 50 "devDependencies": {
49 "expect.js": "^0.3.1", 51 "expect.js": "^0.3.1",
diff --git a/server.js b/server.js
index 67cbd91..68fbb9a 100755
--- a/server.js
+++ b/server.js
@@ -23,6 +23,9 @@ var router = new express.Router();
23 23
24var multipart = multipart({ maxFieldsSize: 2 * 1024, limit: '512mb', timeout: 3 * 60 * 1000 }); 24var multipart = multipart({ maxFieldsSize: 2 * 1024, limit: '512mb', timeout: 3 * 60 * 1000 });
25 25
26router.post ('/api/login', auth.login);
27router.post ('/api/logout', auth.verify, auth.logout);
28router.get ('/api/profile', auth.verify, auth.getProfile);
26router.get ('/api/files/*', auth.verify, files.get); 29router.get ('/api/files/*', auth.verify, files.get);
27router.post ('/api/files/*', auth.verify, multipart, files.post); 30router.post ('/api/files/*', auth.verify, multipart, files.post);
28router.put ('/api/files/*', auth.verify, files.put); 31router.put ('/api/files/*', auth.verify, files.put);
diff --git a/src/auth.js b/src/auth.js
index b56f09f..8645d4c 100644
--- a/src/auth.js
+++ b/src/auth.js
@@ -4,10 +4,25 @@ var passport = require('passport'),
4 path = require('path'), 4 path = require('path'),
5 safe = require('safetydance'), 5 safe = require('safetydance'),
6 bcrypt = require('bcryptjs'), 6 bcrypt = require('bcryptjs'),
7 LdapStrategy = require('passport-ldapjs').Strategy; 7 uuid = require('uuid/v4'),
8 BearerStrategy = require('passport-http-bearer').Strategy,
9 LdapStrategy = require('passport-ldapjs').Strategy,
10 HttpSuccess = require('connect-lastmile').HttpSuccess;
8 11
9var LOCAL_AUTH_FILE = path.resolve(process.env.LOCAL_AUTH_FILE || './.users.json'); 12var LOCAL_AUTH_FILE = path.resolve(process.env.LOCAL_AUTH_FILE || './.users.json');
10 13
14var gTokenStore = {};
15
16function issueAccessToken() {
17 return function (req, res, next) {
18 var accessToken = uuid();
19
20 gTokenStore[accessToken] = req.user;
21
22 next(new HttpSuccess(201, { accessToken: accessToken, user: req.user }));
23 };
24}
25
11passport.serializeUser(function (user, done) { 26passport.serializeUser(function (user, done) {
12 console.log('serializeUser', user); 27 console.log('serializeUser', user);
13 done(null, user.uid); 28 done(null, user.uid);
@@ -24,20 +39,28 @@ var LDAP_USERS_BASE_DN = process.env.LDAP_USERS_BASE_DN;
24if (LDAP_URL && LDAP_USERS_BASE_DN) { 39if (LDAP_URL && LDAP_USERS_BASE_DN) {
25 console.log('Enable ldap auth'); 40 console.log('Enable ldap auth');
26 41
27 exports.verify = passport.authenticate('ldap'); 42 exports.login = [ passport.authenticate('ldap'), issueAccessToken() ];
28} else { 43} else {
29 console.log('Use local user file:', LOCAL_AUTH_FILE); 44 console.log('Use local user file:', LOCAL_AUTH_FILE);
30 45
31 exports.verify = function (req, res, next) { 46 exports.login = [
32 var users = safe.JSON.parse(safe.fs.readFileSync(LOCAL_AUTH_FILE)); 47 function (req, res, next) {
33 if (!users) return res.send(401); 48 var users = safe.JSON.parse(safe.fs.readFileSync(LOCAL_AUTH_FILE));
34 if (!users[req.query.username]) return res.send(401); 49 if (!users) return res.send(401);
50 if (!users[req.query.username]) return res.send(401);
35 51
36 bcrypt.compare(req.query.password, users[req.query.username].passwordHash, function (error, valid) { 52 bcrypt.compare(req.query.password, users[req.query.username].passwordHash, function (error, valid) {
37 if (error || !valid) return res.send(401); 53 if (error || !valid) return res.send(401);
38 next(); 54
39 }); 55 req.user = {
40 }; 56 username: req.query.username
57 };
58
59 next();
60 });
61 },
62 issueAccessToken()
63 ];
41} 64}
42 65
43var opts = { 66var opts = {
@@ -58,3 +81,23 @@ var opts = {
58passport.use(new LdapStrategy(opts, function (profile, done) { 81passport.use(new LdapStrategy(opts, function (profile, done) {
59 done(null, profile); 82 done(null, profile);
60})); 83}));
84
85exports.verify = passport.authenticate('bearer', { session: false });
86
87passport.use(new BearerStrategy(function (token, done) {
88 if (!gTokenStore[token]) return done(null, false);
89
90 return done(null, gTokenStore[token], { accessToken: token });
91}));
92
93exports.logout = function (req, res, next) {
94 console.log(req.authInfo);
95
96 delete gTokenStore[req.authInfo.accessToken];
97
98 next(new HttpSuccess(200, {}));
99};
100
101exports.getProfile = function (req, res, next) {
102 next(new HttpSuccess(200, { username: req.user.username }));
103};