]> git.immae.eu Git - perso/Immae/Projets/Nodejs/Surfer.git/blame - src/auth.js
error is not defined here
[perso/Immae/Projets/Nodejs/Surfer.git] / src / auth.js
CommitLineData
591ad40c
JZ
1'use strict';
2
3var passport = require('passport'),
dcb20866
J
4 path = require('path'),
5 safe = require('safetydance'),
b3ff26fb 6 fs = require('fs'),
dcb20866 7 bcrypt = require('bcryptjs'),
4a27fce7
JZ
8 uuid = require('uuid/v4'),
9 BearerStrategy = require('passport-http-bearer').Strategy,
47ba3ae4 10 ldapjs = require('ldapjs'),
bcee8931 11 HttpError = require('connect-lastmile').HttpError,
7af3d855
JZ
12 HttpSuccess = require('connect-lastmile').HttpSuccess,
13 webdavErrors = require('webdav-server').v2.Errors;
591ad40c 14
47ba3ae4
JZ
15const LDAP_URL = process.env.LDAP_URL;
16const LDAP_USERS_BASE_DN = process.env.LDAP_USERS_BASE_DN;
b3ff26fb
JZ
17const LOCAL_AUTH_FILE = path.resolve(process.env.LOCAL_AUTH_FILE || './.users.json');
18const TOKENSTORE_FILE = path.resolve(process.env.TOKENSTORE_FILE || './.tokens.json');
47ba3ae4
JZ
19const AUTH_METHOD = (LDAP_URL && LDAP_USERS_BASE_DN) ? 'ldap' : 'local';
20
21if (AUTH_METHOD === 'ldap') {
22 console.log('Use ldap auth');
23} else {
24 console.log(`Use local auth file ${LOCAL_AUTH_FILE}`);
25}
dcb20866 26
bcee8931
JZ
27var tokenStore = {
28 data: {},
b3ff26fb
JZ
29 save: function () {
30 try {
31 fs.writeFileSync(TOKENSTORE_FILE, JSON.stringify(tokenStore.data), 'utf-8');
32 } catch (e) {
33 console.error(`Unable to save tokenstore file at ${TOKENSTORE_FILE}`, e);
34 }
35 },
bcee8931
JZ
36 get: function (token, callback) {
37 callback(tokenStore.data[token] ? null : 'not found', tokenStore.data[token]);
38 },
39 set: function (token, data, callback) {
40 tokenStore.data[token] = data;
b3ff26fb 41 tokenStore.save();
bcee8931
JZ
42 callback(null);
43 },
44 del: function (token, callback) {
45 delete tokenStore.data[token];
b3ff26fb 46 tokenStore.save();
bcee8931
JZ
47 callback(null);
48 }
49};
50
b3ff26fb
JZ
51// load token store data if any
52try {
53 console.log(`Using tokenstore file: ${TOKENSTORE_FILE}`);
54 tokenStore.data = JSON.parse(fs.readFileSync(TOKENSTORE_FILE, 'utf-8'));
55} catch (e) {
56 // start with empty token store
bcee8931 57}
4a27fce7
JZ
58
59function issueAccessToken() {
60 return function (req, res, next) {
61 var accessToken = uuid();
62
bcee8931
JZ
63 tokenStore.set(accessToken, req.user, function (error) {
64 if (error) return next(new HttpError(500, error));
65 next(new HttpSuccess(201, { accessToken: accessToken, user: req.user }));
66 });
4a27fce7
JZ
67 };
68}
69
a90a633f
JZ
70passport.serializeUser(function (user, done) {
71 console.log('serializeUser', user);
cfe24a27 72 done(null, user.uid);
a90a633f
JZ
73});
74
75passport.deserializeUser(function (id, done) {
76 console.log('deserializeUser', id);
cfe24a27 77 done(null, { uid: id });
a90a633f
JZ
78});
79
47ba3ae4
JZ
80function verifyUser(username, password, callback) {
81 if (AUTH_METHOD === 'ldap') {
82 var ldapClient = ldapjs.createClient({ url: process.env.LDAP_URL });
83 ldapClient.on('error', function (error) {
84 console.error('LDAP error', error);
85 });
591ad40c 86
47ba3ae4
JZ
87 ldapClient.bind(process.env.LDAP_BIND_DN, process.env.LDAP_BIND_PASSWORD, function (error) {
88 if (error) return callback(error);
591ad40c 89
47ba3ae4
JZ
90 var filter = `(|(uid=${username})(mail=${username})(username=${username})(sAMAccountName=${username}))`;
91 ldapClient.search(process.env.LDAP_USERS_BASE_DN, { filter: filter }, function (error, result) {
92 if (error) return callback(error);
a90a633f 93
47ba3ae4 94 var items = [];
dcb20866 95
47ba3ae4
JZ
96 result.on('searchEntry', function(entry) { items.push(entry.object); });
97 result.on('error', callback);
98 result.on('end', function (result) {
8dc61bb6 99 if (result.status !== 0 || items.length === 0) return callback('Invalid credentials');
4a27fce7 100
47ba3ae4
JZ
101 // pick the first found
102 var user = items[0];
4a27fce7 103
47ba3ae4
JZ
104 ldapClient.bind(user.dn, password, function (error) {
105 if (error) return callback('Invalid credentials');
106
107 callback(null, { username: username });
108 });
109 });
4a27fce7 110 });
47ba3ae4
JZ
111 });
112 } else {
113 var users = safe.JSON.parse(safe.fs.readFileSync(LOCAL_AUTH_FILE));
114 if (!users || !users[username]) return callback('Invalid credentials');
115
116 bcrypt.compare(password, users[username].passwordHash, function (error, valid) {
117 if (error || !valid) return callback('Invalid credentials');
118
119 callback(null, { username: username });
120 });
121 }
591ad40c
JZ
122}
123
47ba3ae4
JZ
124exports.login = [
125 function (req, res, next) {
126 verifyUser(req.body.username, req.body.password, function (error, user) {
127 if (error) return next(new HttpError(401, 'Invalid credentials'));
591ad40c 128
47ba3ae4
JZ
129 req.user = user;
130
131 next();
132 });
133 },
134 issueAccessToken()
135];
4a27fce7
JZ
136
137exports.verify = passport.authenticate('bearer', { session: false });
138
139passport.use(new BearerStrategy(function (token, done) {
bcee8931
JZ
140 tokenStore.get(token, function (error, result) {
141 if (error) {
142 console.error(error);
143 return done(null, false);
144 }
145
146 done(null, result, { accessToken: token });
147 });
4a27fce7
JZ
148}));
149
150exports.logout = function (req, res, next) {
bcee8931
JZ
151 tokenStore.del(req.authInfo.accessToken, function (error) {
152 if (error) console.error(error);
4a27fce7 153
bcee8931
JZ
154 next(new HttpSuccess(200, {}));
155 });
4a27fce7
JZ
156};
157
158exports.getProfile = function (req, res, next) {
159 next(new HttpSuccess(200, { username: req.user.username }));
160};
7af3d855
JZ
161
162// webdav usermanager
163exports.WebdavUserManager = WebdavUserManager;
164
165// This implements the required interface only for the Basic Authentication for webdav-server
166function WebdavUserManager() {};
167
168WebdavUserManager.prototype.getDefaultUser = function (callback) {
169 // this is only a dummy user, since we always require authentication
170 var user = {
171 username: 'DefaultUser',
172 password: null,
173 isAdministrator: false,
174 isDefaultUser: true,
175 uid: 'DefaultUser'
176 };
177
178 callback(user);
179};
180
181WebdavUserManager.prototype.getUserByNamePassword = function (username, password, callback) {
47ba3ae4
JZ
182 verifyUser(username, password, function (error, user) {
183 if (error) return callback(webdavErrors.UserNotFound);
7af3d855
JZ
184
185 callback(null, {
47ba3ae4 186 username: user.username,
7af3d855
JZ
187 isAdministrator: true,
188 isDefaultUser: false,
47ba3ae4 189 uid: user.username
7af3d855
JZ
190 });
191 });
192};