1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Tie auth middleware to needsPermission api

This commit is contained in:
Nick O'Leary 2015-02-05 23:43:35 +00:00
parent 3ef6f29d6e
commit c31ffb98b0
11 changed files with 36 additions and 135 deletions

View File

@ -23,6 +23,7 @@
"dependencies": {
"express": "3.17.2",
"when": "3.4.6",
"bcryptjs": "2.1.0",
"nopt": "3.0.1",
"mqtt": "0.3.x",
"ws": "0.4.32",

View File

@ -20,8 +20,9 @@ var oauth2orize = require("oauth2orize");
var strategies = require("./strategies");
var Tokens = require("./tokens");
var Users = require("./users");
var permissions = require("./permissions");
var settings = require("../../settings");
var settings = null;
var log = require("../../log");
@ -33,24 +34,31 @@ var server = oauth2orize.createServer();
server.exchange(oauth2orize.exchange.password(strategies.passwordTokenExchange));
function init() {
function init(_settings) {
settings = _settings;
if (settings.adminAuth) {
Users.init(settings.adminAuth);
Tokens.init(settings)
}
}
function authenticate(req,res,next) {
function needsPermission(permission) {
return function(req,res,next) {
if (settings.adminAuth) {
if (/^\/auth\/.*/.test(req.originalUrl)) {
next();
} else {
return passport.authenticate(['bearer','anon'], { session: false })(req,res,next);
return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() {
if (!req.user) {
return next();
}
if (permissions.hasPermission(req.user,permission)) {
return next();
}
return res.send(401);
});
} else {
next();
}
}
}
function ensureClientSecret(req,res,next) {
if (!req.body.client_secret) {
@ -83,7 +91,7 @@ function revoke(req,res) {
module.exports = {
init: init,
authenticate: authenticate,
needsPermission: needsPermission,
ensureClientSecret: ensureClientSecret,
authenticateClient: authenticateClient,
getToken: getToken,

View File

@ -19,18 +19,6 @@ var util = require('util');
var readRE = /^((.+)\.)?read$/
var writeRE = /^((.+)\.)?write$/
function needsPermission(perm) {
return function(req,res,next) {
if (!req.user) {
return next();
}
if (hasPermission(req.user,perm)) {
return next();
}
return res.send(401);
}
}
function hasPermission(user,permission) {
if (!user.permissions) {
return false;
@ -45,6 +33,4 @@ function hasPermission(user,permission) {
module.exports = {
hasPermission: hasPermission,
needsPermission: needsPermission,
}

View File

@ -15,30 +15,8 @@
**/
var when = require("when");
var crypto = require("crypto");
var util = require("util");
/*
adminAuth: {
type: "credentials",
users: [{
username: "nol",
password: "5f4dcc3b5aa765d61d8327deb882cf99" // password
permissions: "* read write"
}],
default: {
permissions: "* read write"
}
},
adminAuth: {
type: "credentials",
users: function(username) {return when.resolve(user)},
authenticate: function(username,password) { return when.resolve(user);}
default: function() { return when.resolve(defaultUser) }
}
*/
//{username:"nick",password:crypto.createHash('md5').update("foo",'utf8').digest('hex')}
var bcrypt = require('bcryptjs');
var users = {};
var passwords = {};
@ -47,10 +25,11 @@ var defaultUser = null;
function authenticate(username,password) {
var user = users[username];
if (user) {
var pass = crypto.createHash('md5').update(password,'utf8').digest('hex');
if (pass == passwords[username]) {
return when.resolve(user);
}
return when.promise(function(resolve,reject) {
bcrypt.compare(password, passwords[username], function(err, res) {
resolve(res?user:null);
});
});
}
return when.resolve(null);
}

View File

@ -26,7 +26,7 @@ var library = require("./library");
var info = require("./info");
var auth = require("./auth");
var needsPermission = require("./auth/permissions").needsPermission;
var needsPermission = auth.needsPermission;
var settings = require("../settings");
@ -38,7 +38,7 @@ var errorHandler = function(err,req,res,next) {
function init(adminApp) {
auth.init();
auth.init(settings);
// Editor
if (!settings.disableEditor) {
@ -55,7 +55,6 @@ function init(adminApp) {
if (settings.adminAuth) {
//TODO: all passport references ought to be in ./auth
adminApp.use(passport.initialize());
adminApp.use(auth.authenticate);
adminApp.post("/auth/token",
auth.ensureClientSecret,
auth.authenticateClient,

View File

@ -17,10 +17,11 @@
var redApp = null;
var storage = require("../storage");
var log = require("../log");
var needsPermission = require("./auth").needsPermission;
function createLibrary(type) {
if (redApp) {
redApp.get(new RegExp("/library/"+type+"($|\/(.*))"),function(req,res) {
redApp.get(new RegExp("/library/"+type+"($|\/(.*))"),needsPermission("library.read"),function(req,res) {
var path = req.params[1]||"";
storage.getLibraryEntry(type,path).then(function(result) {
if (typeof result === "string") {
@ -42,7 +43,7 @@ function createLibrary(type) {
});
});
redApp.post(new RegExp("/library/"+type+"\/(.*)"),function(req,res) {
redApp.post(new RegExp("/library/"+type+"\/(.*)"),needsPermission("library.write"),function(req,res) {
var path = req.params[0];
var fullBody = '';
req.on('data', function(chunk) {

View File

@ -23,7 +23,7 @@ var util = require("./util");
var fs = require("fs");
var settings = require("./settings");
var credentials = require("./nodes/credentials");
var permissions = require("./api/auth/permissions");
var auth = require("./api/auth");
var path = require('path');
@ -52,7 +52,7 @@ var RED = {
settings:settings,
util: util,
auth: {
needsPermission: permissions.needsPermission
needsPermission: auth.needsPermission
},
version: function () {
var p = require(path.join(process.env.NODE_RED_HOME,"package.json"));

View File

@ -27,59 +27,6 @@ var settings = require("../../../../red/settings");
describe("api auth middleware",function() {
describe("authenticate",function() {
it("does not trigger on auth paths", sinon.test(function(done) {
this.stub(passport,"authenticate",function() {
return function() {
settings.reset();
done(new Error("authentication not applied to auth path"));
}
});
settings.init({adminAuth:{}});
var req = {
originalUrl: "/auth/token"
};
auth.authenticate(req,null,function() {
settings.reset();
done();
});
}));
it("does trigger on non-auth paths", sinon.test(function(done) {
this.stub(passport,"authenticate",function() {
return function() {
settings.reset();
done();
}
});
settings.init({adminAuth:{}});
var req = {
originalUrl: "/"
};
auth.authenticate(req,null,function() {
settings.reset();
done(new Error("authentication applied to non-auth path"));
});
}));
it("does not trigger on non-auth paths with auth disabled", sinon.test(function(done) {
this.stub(passport,"authenticate",function() {
return function() {
settings.reset();
done(new Error("authentication applied when disabled"));
}
});
settings.init({});
var req = {
originalUrl: "/"
};
auth.authenticate(req,null,function() {
settings.reset();
done();
});
}));
});
describe("ensureClientSecret", function() {
it("leaves client_secret alone if not present",function(done) {

View File

@ -35,27 +35,4 @@ describe("Auth permissions", function() {
permissions.hasPermission({permissions:"read"},"node.write").should.be.false;
});
});
describe("needsPermission middleware", function() {
it('passes if no user on request',function(done) {
var needsPermission = permissions.needsPermission("*");
needsPermission({},null,function() {
done();
});
});
it('passes if user has required permission',function(done) {
var needsPermission = permissions.needsPermission("read");
needsPermission({user:{permissions:"read"}},null,function() {
done();
});
});
it('rejects if user does not have required permission',function(done) {
var needsPermission = permissions.needsPermission("write");
needsPermission({user:{permissions:"read"}},{send: function(code) {
code.should.equal(401);
done();
}},null);
});
});
});

View File

@ -27,7 +27,8 @@ describe("Users", function() {
type:"credentials",
users:[{
username:"fred",
password:"5f4dcc3b5aa765d61d8327deb882cf99", // 'password'
password:'$2a$08$LpYMefvGZ3MjAfZGzcoyR.1BcfHh4wy4NpbN.cEny5aHnWOqjKOXK',
// 'password' -> require('bcryptjs').hashSync('password', 8);
permissions:"*"
}]
});

View File

@ -24,6 +24,7 @@ var app = express();
var RED = require("../../../red/red.js");
var storage = require("../../../red/storage");
var library = require("../../../red/api/library");
var auth = require("../../../red/api/auth");
describe("library api", function() {
@ -166,6 +167,7 @@ describe("library api", function() {
app = express();
app.use(express.json());
library.init(app);
auth.init({});
RED.library.register("test");
});