Allow adminAuth.user to be a Function

Fixes #1461
This commit is contained in:
Nick O'Leary 2018-01-23 23:08:11 +00:00
parent cc9011cd68
commit 3cb5cbd8d5
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
4 changed files with 97 additions and 91 deletions

View File

@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var when = require("when");
var clients = [
{id:"node-red-editor",secret:"not_available"},
@ -25,9 +23,9 @@ module.exports = {
get: function(id) {
for (var i=0;i<clients.length;i++) {
if (clients[i].id == id) {
return when.resolve(clients[i]);
return Promise.resolve(clients[i]);
}
}
return when.resolve(null);
return Promise.resolve(null);
}
}

View File

@ -135,6 +135,66 @@ function completeVerify(profile,done) {
});
}
function genericStrategy(adminApp,strategy) {
var crypto = require("crypto")
var session = require('express-session')
var MemoryStore = require('memorystore')(session)
adminApp.use(session({
// As the session is only used across the life-span of an auth
// hand-shake, we can use a instance specific random string
secret: crypto.randomBytes(20).toString('hex'),
resave: false,
saveUninitialized: false,
store: new MemoryStore({
checkPeriod: 86400000 // prune expired entries every 24h
})
}));
//TODO: all passport references ought to be in ./auth
adminApp.use(passport.initialize());
adminApp.use(passport.session());
var options = strategy.options;
passport.use(new strategy.strategy(options,
function() {
var originalDone = arguments[arguments.length-1];
if (options.verify) {
var args = Array.from(arguments);
args[args.length-1] = function(err,profile) {
if (err) {
return originalDone(err);
} else {
return completeVerify(profile,originalDone);
}
};
options.verify.apply(null,args);
} else {
var profile = arguments[arguments.length - 2];
return completeVerify(profile,originalDone);
}
}
));
adminApp.get('/auth/strategy',
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
completeGenerateStrategyAuth
);
adminApp.get('/auth/strategy/callback',
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
completeGenerateStrategyAuth
);
}
function completeGenerateStrategyAuth(req,res) {
var tokens = req.user.tokens;
delete req.user.tokens;
// Successful authentication, redirect home.
res.redirect(settings.httpAdminRoot + '?access_token='+tokens.accessToken);
}
module.exports = {
init: init,
needsPermission: needsPermission,
@ -149,58 +209,5 @@ module.exports = {
},
login: login,
revoke: revoke,
genericStrategy: function(adminApp,strategy) {
var crypto = require("crypto")
var session = require('express-session')
var MemoryStore = require('memorystore')(session)
adminApp.use(session({
// As the session is only used across the life-span of an auth
// hand-shake, we can use a instance specific random string
secret: crypto.randomBytes(20).toString('hex'),
resave: false,
saveUninitialized: false,
store: new MemoryStore({
checkPeriod: 86400000 // prune expired entries every 24h
})
}));
//TODO: all passport references ought to be in ./auth
adminApp.use(passport.initialize());
adminApp.use(passport.session());
var options = strategy.options;
passport.use(new strategy.strategy(options,
function() {
var originalDone = arguments[arguments.length-1];
if (options.verify) {
var args = Array.prototype.slice.call(arguments);
args[args.length-1] = function(err,profile) {
if (err) {
return originalDone(err);
} else {
return completeVerify(profile,originalDone);
}
};
options.verify.apply(null,args);
} else {
var profile = arguments[arguments.length - 2];
return completeVerify(profile,originalDone);
}
}
));
adminApp.get('/auth/strategy', passport.authenticate(strategy.name));
adminApp.get('/auth/strategy/callback',
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
function(req, res) {
var tokens = req.user.tokens;
delete req.user.tokens;
// Successful authentication, redirect home.
res.redirect(settings.httpAdminRoot + '?access_token='+tokens.accessToken);
}
);
}
genericStrategy: genericStrategy
}

View File

@ -14,8 +14,6 @@
* limitations under the License.
**/
var when = require("when");
function generateToken(length) {
var c = "ABCDEFGHIJKLMNOPQRSTUZWXYZabcdefghijklmnopqrstuvwxyz1234567890";
var token = [];
@ -49,7 +47,7 @@ function expireSessions() {
if (modified) {
return storage.saveSessions(sessions);
} else {
return when.resolve();
return Promise.resolve();
}
}
function loadSessions() {
@ -69,7 +67,7 @@ module.exports = {
// At this point, storage will not have been initialised, so defer loading
// the sessions until there's a request for them.
loadedSessions = null;
return when.resolve();
return Promise.resolve();
},
get: function(token) {
return loadSessions().then(function() {
@ -78,7 +76,7 @@ module.exports = {
return expireSessions().then(function() { return null });
}
}
return when.resolve(sessions[token]);
return Promise.resolve(sessions[token]);
});
},
create: function(user,client,scope) {

View File

@ -14,13 +14,12 @@
* limitations under the License.
**/
var when = require("when");
var util = require("util");
var clone = require("clone");
var bcrypt;
try { bcrypt = require('bcrypt'); }
catch(e) { bcrypt = require('bcryptjs'); }
var users = {};
var passwords = {};
var defaultUser = null;
function authenticate() {
@ -28,31 +27,33 @@ function authenticate() {
if (typeof username !== 'string') {
username = username.username;
}
var user = users[username];
if (user) {
if (arguments.length === 2) {
// Username/password authentication
var password = arguments[1];
return when.promise(function(resolve,reject) {
bcrypt.compare(password, passwords[username], function(err, res) {
resolve(res?user:null);
const args = Array.from(arguments);
return api.get(username).then(function(user) {
if (user) {
if (args.length === 2) {
// Username/password authentication
var password = args[1];
return new Promise(function(resolve,reject) {
bcrypt.compare(password, user.password, function(err, res) {
resolve(res?cleanUser(user):null);
});
});
});
} else {
// Try to extract common profile information
if (arguments[0].hasOwnProperty('photos') && arguments[0].photos.length > 0) {
user.image = arguments[0].photos[0].value;
} else {
// Try to extract common profile information
if (args[0].hasOwnProperty('photos') && args[0].photos.length > 0) {
user.image = args[0].photos[0].value;
}
return cleanUser(user);
}
return when.resolve(user);
}
}
return when.resolve(null);
return null;
});
}
function get(username) {
return when.resolve(users[username]);
return Promise.resolve(users[username]);
}
function getDefaultUser() {
return when.resolve(null);
return Promise.resolve(null);
}
var api = {
@ -63,7 +64,6 @@ var api = {
function init(config) {
users = {};
passwords = {};
defaultUser = null;
if (config.type == "credentials" || config.type == "strategy") {
if (config.users) {
@ -77,11 +77,7 @@ function init(config) {
}
for (var i=0;i<us.length;i++) {
var u = us[i];
users[u.username] = {
"username":u.username,
"permissions":u.permissions
};
passwords[u.username] = u.password;
users[u.username] = clone(u);
}
}
}
@ -96,7 +92,7 @@ function init(config) {
api.default = config.default;
} else {
api.default = function() {
return when.resolve({
return Promise.resolve({
"anonymous": true,
"permissions":config.default.permissions
});
@ -106,10 +102,17 @@ function init(config) {
api.default = getDefaultUser;
}
}
function cleanUser(user) {
if (user && user.hasOwnProperty('password')) {
user = clone(user);
delete user.password;
}
return user;
}
module.exports = {
init: init,
get: function(username) { return api.get(username) },
get: function(username) { return api.get(username).then(cleanUser)},
authenticate: function() { return api.authenticate.apply(null, arguments) },
default: function() { return api.default(); }
};