Merge branch 'cloudron-io-master'

This commit is contained in:
Andris Reinman 2016-08-29 13:02:20 +03:00
commit 3fcd389db8
8 changed files with 209 additions and 76 deletions

4
app.js
View file

@ -135,6 +135,10 @@ passport.setup(app);
app.use((req, res, next) => {
res.locals.flash = req.flash.bind(req);
res.locals.user = req.user;
res.locals.ldap = {
enabled: config.ldap.enabled,
passwordresetlink: config.ldap.passwordresetlink
};
let menu = [{
title: 'Home',

View file

@ -87,3 +87,12 @@ host="0.0.0.0"
username="testuser"
password="testpass"
logger=false
[ldap]
# enable to use ldap user backend
enabled=false
host="localhost"
port=3002
baseDN="ou=users,dc=company"
filter="(|(username={{username}})(mail={{username}}))"
passwordresetlink=""

View file

@ -61,6 +61,52 @@ module.exports.findByAccessToken = (accessToken, callback) => {
});
};
module.exports.findByUsername = (username, callback) => {
db.getConnection((err, connection) => {
if (err) {
return callback(err);
}
connection.query('SELECT `id`, `username`, `email`, `access_token` FROM `users` WHERE `username`=? LIMIT 1', [username], (err, rows) => {
connection.release();
if (err) {
return callback(err);
}
if (!rows.length) {
return callback(null, false);
}
let user = tools.convertKeys(rows[0]);
return callback(null, user);
});
});
};
module.exports.add = (username, password, email, callback) => {
db.getConnection((err, connection) => {
if (err) {
return callback(err);
}
connection.query('INSERT INTO `users` (`username`, `password`, `email`, `created`) VALUES (?, ?, ?, NOW())', [username, password, email], (err, result) => {
connection.release();
if (err) {
return callback(err);
}
let id = result && result.insertId;
if (!id) {
return callback(new Error('Could not store user row'));
}
return callback(null, id);
});
});
};
/**
* Fetches user by username and password
*
@ -70,6 +116,10 @@ module.exports.findByAccessToken = (accessToken, callback) => {
*/
module.exports.authenticate = (username, password, callback) => {
if (password === '') {
return callback(null, false);
}
let login = (connection, callback) => {
connection.query('SELECT `id`, `password`, `access_token` FROM `users` WHERE `username`=? OR email=? LIMIT 1', [username, username], (err, rows) => {
if (err) {

View file

@ -1,8 +1,11 @@
'use strict';
let config = require('config');
let log = require('npmlog');
let passport = require('passport');
let LocalStrategy = require('passport-local').Strategy;
let LdapStrategy = require('passport-ldapjs').Strategy;
let csrf = require('csurf');
let bodyParser = require('body-parser');
let users = require('./models/users');
@ -30,7 +33,7 @@ module.exports.logout = (req, res) => {
};
module.exports.login = (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
passport.authenticate(config.ldap.enabled ? 'ldap' : 'local', (err, user, info) => {
if (err) {
req.flash('danger', err.message);
return next(err);
@ -58,21 +61,66 @@ module.exports.login = (req, res, next) => {
})(req, res, next);
};
passport.use(new LocalStrategy((username, password, done) => {
users.authenticate(username, password, (err, user) => {
if (err) {
return done(err);
}
if (config.ldap.enabled) {
log.info('Using LDAP auth');
if (!user) {
return done(null, false, {
message: 'Incorrect username or password'
});
var opts = {
server: {
url: 'ldap://' + config.ldap.host + ':' + config.ldap.port,
},
base: config.ldap.baseDN,
search: {
filter: config.ldap.filter,
attributes: ['username', 'mail'],
scope: 'sub'
}
};
return done(null, user);
});
}));
passport.use(new LdapStrategy(opts, function (profile, done) {
users.findByUsername(profile.username, (err, user) => {
if (err) {
return done(err);
}
if (!user) {
// password is empty for ldap
users.add(profile.username, '', profile.mail, (err, id) => {
if (err) {
return done(err);
}
return done(null, {
id: id,
username: profile.username
});
});
} else {
return done(null, {
id: user.id,
username: user.username
});
}
});
}));
} else {
log.info('Using local auth');
passport.use(new LocalStrategy((username, password, done) => {
users.authenticate(username, password, (err, user) => {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
message: 'Incorrect username or password'
});
}
return done(null, user);
});
}));
}
passport.serializeUser((user, done) => {
done(null, user.id);

View file

@ -65,6 +65,7 @@
"npmlog": "^4.0.0",
"openpgp": "^2.3.3",
"passport": "^0.3.2",
"passport-ldapjs": "^1.0.2",
"passport-local": "^1.0.0",
"request": "^2.74.0",
"serve-favicon": "^2.3.0",

View file

@ -7,58 +7,66 @@
<hr>
<form class="form-horizontal" method="post" action="/users/account">
{{#if ldap.enabled}}
<p>
This account is managed through LDAP.<br/>
<br/>
Associated Email Address: <a href="mailto:{{email}}">{{email}}</a>
</p>
{{else}}
<form class="form-horizontal" method="post" action="/users/account">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<fieldset>
<legend>
General Settings
</legend>
<fieldset>
<legend>
General Settings
</legend>
<div class="form-group">
<label for="email" class="col-sm-2 control-label">Email Address</label>
<div class="col-sm-10">
<input type="email" class="form-control" name="email" id="email" value="{{email}}" placeholder="Your e-mail address" required>
<span class="help-block">This address is used for account recovery in case you loose your password</span>
</div>
</div>
</fieldset>
<fieldset>
<legend>
Password change
</legend>
<p>
You only need to fill out this form if you want to change your current password
</p>
<div class="form-group">
<label for="currentPassword" class="col-sm-2 control-label">Current Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="currentPassword" id="currentPassword" placeholder="Current Password">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">New Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password" id="password" placeholder="New Password">
</div>
</div>
<div class="form-group">
<label for="password2" class="col-sm-2 control-label">Confirm Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password2" id="password2" placeholder="Confirm New Password">
</div>
</div>
</fieldset>
<div class="form-group">
<label for="email" class="col-sm-2 control-label">Email Address</label>
<div class="col-sm-10">
<input type="email" class="form-control" name="email" id="email" value="{{email}}" placeholder="Your e-mail address" required>
<span class="help-block">This address is used for account recovery in case you loose your password</span>
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-ok"></i> Update</button>
</div>
</div>
</fieldset>
<fieldset>
<legend>
Password change
</legend>
<p>
You only need to fill out this form if you want to change your current password
</p>
<div class="form-group">
<label for="currentPassword" class="col-sm-2 control-label">Current Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="currentPassword" id="currentPassword" placeholder="Current Password">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">New Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password" id="password" placeholder="New Password">
</div>
</div>
<div class="form-group">
<label for="password2" class="col-sm-2 control-label">Confirm Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password2" id="password2" placeholder="Confirm New Password">
</div>
</div>
</fieldset>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-ok"></i> Update</button>
</div>
</div>
</form>
</form>
{{/if}}

View file

@ -8,22 +8,30 @@
<hr>
<p>Please provide the username or email address that you used when you signed up for your Mailtrain account.</p>
<p>We will send you an email that will allow you to reset your password.</p>
{{#if ldap.enabled}}
<p>
Accounts are managed through LDAP.<br/>
<br/>
<a href="{{ldap.passwordresetlink}}">Reset Password</a>
</p>
{{else}}
<p>Please provide the username or email address that you used when you signed up for your Mailtrain account.</p>
<p>We will send you an email that will allow you to reset your password.</p>
<form class="form-horizontal" role="login" method="post" action="/users/forgot">
<form class="form-horizontal" role="login" method="post" action="/users/forgot">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<div class="form-group">
<label for="usernameMain" class="col-sm-2 control-label">Username</label>
<div class="col-xs-4">
<input type="text" class="form-control" name="username" id="usernameMain" placeholder="Username or email address" autofocus required>
<div class="form-group">
<label for="usernameMain" class="col-sm-2 control-label">Username</label>
<div class="col-xs-4">
<input type="text" class="form-control" name="username" id="usernameMain" placeholder="Username or email address" autofocus required>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-xs-4">
<button type="submit" class="btn btn-primary">Send verification email</button>
<div class="form-group">
<div class="col-sm-offset-2 col-xs-4">
<button type="submit" class="btn btn-primary">Send verification email</button>
</div>
</div>
</div>
</form>
</form>
{{/if}}

View file

@ -32,7 +32,12 @@
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-xs-4">
<button type="submit" class="btn btn-primary">Sign in</button> or <a href="/users/forgot">Forgot password?</a>
<button type="submit" class="btn btn-primary">Sign in</button> or
{{#if ldap.enabled}}
<a href="{{ldap.passwordresetlink}}">Forgot password?</a>
{{else}}
<a href="/users/forgot">Forgot password?</a>
{{/if}}
</div>
</div>
</form>