-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathAuthentication.js
148 lines (136 loc) · 4.42 KB
/
Authentication.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
'use strict';
var bcrypt = require('bcryptjs');
var csrf = require('csurf');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
const OTPAuth = require('otpauth')
/**
* Constructor for Authentication class
*
* @class Authentication
* @param {Object[]} validUsers
* @param {boolean} useEncryptedPasswords
*/
function Authentication(validUsers, useEncryptedPasswords, mountPath) {
this.validUsers = validUsers;
this.useEncryptedPasswords = useEncryptedPasswords || false;
this.mountPath = mountPath;
}
function initialize(app, options) {
options = options || {};
var self = this;
passport.use('local', new LocalStrategy(
{passReqToCallback:true},
function(req, username, password, cb) {
var match = self.authenticate({
name: username,
pass: password,
otpCode: req.body.otpCode
});
if (!match.matchingUsername) {
return cb(null, false, { message: JSON.stringify({ text: 'Invalid username or password' }) });
}
if (!match.otpValid) {
return cb(null, false, { message: JSON.stringify({ text: 'Invalid one-time password.', otpLength: match.otpMissingLength || 6}) });
}
if (match.otpMissingLength) {
return cb(null, false, { message: JSON.stringify({ text: 'Please enter your one-time password.', otpLength: match.otpMissingLength || 6 })});
}
cb(null, match.matchingUsername);
})
);
passport.serializeUser(function(username, cb) {
cb(null, username);
});
passport.deserializeUser(function(username, cb) {
var user = self.authenticate({
name: username
}, true);
cb(null, user);
});
var cookieSessionSecret = options.cookieSessionSecret || require('crypto').randomBytes(64).toString('hex');
app.use(require('connect-flash')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(require('cookie-session')({
key : 'parse_dash',
secret : cookieSessionSecret,
cookie : {
maxAge: (2 * 7 * 24 * 60 * 60 * 1000) // 2 weeks
}
}));
app.use(passport.initialize());
app.use(passport.session());
app.post('/login',
csrf(),
passport.authenticate('local', {
successRedirect: `${self.mountPath}apps`,
failureRedirect: `${self.mountPath}login`,
failureFlash : true
})
);
app.get('/logout', function(req, res){
req.logout();
res.redirect(`${self.mountPath}login`);
});
}
/**
* Authenticates the `userToTest`
*
* @param {Object} userToTest
* @returns {Object} Object with `isAuthenticated` and `appsUserHasAccessTo` properties
*/
function authenticate(userToTest, usernameOnly) {
let appsUserHasAccessTo = null;
let matchingUsername = null;
let isReadOnly = false;
let otpMissingLength = false;
let otpValid = true;
//they provided auth
let isAuthenticated = userToTest &&
//there are configured users
this.validUsers &&
//the provided auth matches one of the users
this.validUsers.find(user => {
let isAuthenticated = false;
let usernameMatches = userToTest.name == user.user;
if (usernameMatches && user.mfa && !usernameOnly) {
if (!userToTest.otpCode) {
otpMissingLength = user.mfaDigits || 6;
} else {
const totp = new OTPAuth.TOTP({
algorithm: user.mfaAlgorithm || 'SHA1',
secret: OTPAuth.Secret.fromBase32(user.mfa),
digits: user.mfaDigits,
period: user.mfaPeriod,
});
const valid = totp.validate({
token: userToTest.otpCode
});
if (valid === null) {
otpValid = false;
otpMissingLength = user.mfaDigits || 6;
}
}
}
let passwordMatches = this.useEncryptedPasswords && !usernameOnly ? bcrypt.compareSync(userToTest.pass, user.pass) : userToTest.pass == user.pass;
if (usernameMatches && (usernameOnly || passwordMatches)) {
isAuthenticated = true;
matchingUsername = user.user;
// User restricted apps
appsUserHasAccessTo = user.apps || null;
isReadOnly = !!user.readOnly; // make it true/false
}
return isAuthenticated;
}) ? true : false;
return {
isAuthenticated,
matchingUsername,
otpMissingLength,
otpValid,
appsUserHasAccessTo,
isReadOnly,
};
}
Authentication.prototype.initialize = initialize;
Authentication.prototype.authenticate = authenticate;
module.exports = Authentication;