mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #2479 from node-red-hitachi/dev-admin-api-auth
Add admin api authentication function
This commit is contained in:
commit
6912dec166
@ -36,6 +36,7 @@ var log = require("@node-red/util").log; // TODO: separate module
|
|||||||
passport.use(strategies.bearerStrategy.BearerStrategy);
|
passport.use(strategies.bearerStrategy.BearerStrategy);
|
||||||
passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy);
|
passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy);
|
||||||
passport.use(strategies.anonymousStrategy);
|
passport.use(strategies.anonymousStrategy);
|
||||||
|
passport.use(strategies.tokensStrategy);
|
||||||
|
|
||||||
var server = oauth2orize.createServer();
|
var server = oauth2orize.createServer();
|
||||||
|
|
||||||
@ -60,7 +61,7 @@ function init(_settings,storage) {
|
|||||||
function needsPermission(permission) {
|
function needsPermission(permission) {
|
||||||
return function(req,res,next) {
|
return function(req,res,next) {
|
||||||
if (settings && settings.adminAuth) {
|
if (settings && settings.adminAuth) {
|
||||||
return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() {
|
return passport.authenticate(['bearer','tokens','anon'],{ session: false })(req,res,function() {
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
@ -123,9 +123,38 @@ AnonymousStrategy.prototype.authenticate = function(req) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function TokensStrategy() {
|
||||||
|
passport.Strategy.call(this);
|
||||||
|
this.name = 'tokens';
|
||||||
|
}
|
||||||
|
util.inherits(TokensStrategy, passport.Strategy);
|
||||||
|
TokensStrategy.prototype.authenticate = function(req) {
|
||||||
|
var self = this;
|
||||||
|
var token = null;
|
||||||
|
if (Users.tokenHeader() === 'authorization') {
|
||||||
|
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
|
||||||
|
token = req.headers.authorization.split(' ')[1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
token = req.headers[Users.tokenHeader()];
|
||||||
|
}
|
||||||
|
if (token) {
|
||||||
|
Users.tokens(token).then(function(admin) {
|
||||||
|
if (admin) {
|
||||||
|
self.success(admin,{scope:admin.permissions});
|
||||||
|
} else {
|
||||||
|
self.fail(401);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.fail(401);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
bearerStrategy: bearerStrategy,
|
bearerStrategy: bearerStrategy,
|
||||||
clientPasswordStrategy: clientPasswordStrategy,
|
clientPasswordStrategy: clientPasswordStrategy,
|
||||||
passwordTokenExchange: passwordTokenExchange,
|
passwordTokenExchange: passwordTokenExchange,
|
||||||
anonymousStrategy: new AnonymousStrategy()
|
anonymousStrategy: new AnonymousStrategy(),
|
||||||
|
tokensStrategy: new TokensStrategy()
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,9 @@ function getDefaultUser() {
|
|||||||
var api = {
|
var api = {
|
||||||
get: get,
|
get: get,
|
||||||
authenticate: authenticate,
|
authenticate: authenticate,
|
||||||
default: getDefaultUser
|
default: getDefaultUser,
|
||||||
|
tokens: getDefaultUser,
|
||||||
|
tokenHeader: "authorization"
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(config) {
|
function init(config) {
|
||||||
@ -105,6 +107,12 @@ function init(config) {
|
|||||||
} else {
|
} else {
|
||||||
api.default = getDefaultUser;
|
api.default = getDefaultUser;
|
||||||
}
|
}
|
||||||
|
if (config.tokens && typeof config.tokens === "function") {
|
||||||
|
api.tokens = config.tokens;
|
||||||
|
if (config.tokenHeader && typeof config.tokenHeader === "string") {
|
||||||
|
api.tokenHeader = config.tokenHeader.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function cleanUser(user) {
|
function cleanUser(user) {
|
||||||
if (user && user.hasOwnProperty('password')) {
|
if (user && user.hasOwnProperty('password')) {
|
||||||
@ -118,5 +126,7 @@ module.exports = {
|
|||||||
init: init,
|
init: init,
|
||||||
get: function(username) { return api.get(username).then(cleanUser)},
|
get: function(username) { return api.get(username).then(cleanUser)},
|
||||||
authenticate: function() { return api.authenticate.apply(null, arguments) },
|
authenticate: function() { return api.authenticate.apply(null, arguments) },
|
||||||
default: function() { return api.default(); }
|
default: function() { return api.default(); },
|
||||||
|
tokens: function(token) { return api.tokens(token); },
|
||||||
|
tokenHeader: function() { return api.tokenHeader }
|
||||||
};
|
};
|
||||||
|
@ -129,6 +129,61 @@ describe("api/auth/strategies", function() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Tokens Strategy", function() {
|
||||||
|
it('Succeeds if tokens user enabled custom header',function(done) {
|
||||||
|
var userTokens = sinon.stub(Users,"tokens",function(token) {
|
||||||
|
return when.resolve("tokens-"+token);
|
||||||
|
});
|
||||||
|
var userTokenHeader = sinon.stub(Users,"tokenHeader",function(token) {
|
||||||
|
return "x-test-token";
|
||||||
|
});
|
||||||
|
strategies.tokensStrategy._success = strategies.tokensStrategy.success;
|
||||||
|
strategies.tokensStrategy.success = function(user) {
|
||||||
|
user.should.equal("tokens-1234");
|
||||||
|
strategies.tokensStrategy.success = strategies.tokensStrategy._success;
|
||||||
|
delete strategies.tokensStrategy._success;
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
strategies.tokensStrategy.authenticate({headers:{"x-test-token":"1234"}});
|
||||||
|
});
|
||||||
|
it('Succeeds if tokens user enabled default header',function(done) {
|
||||||
|
var userTokens = sinon.stub(Users,"tokens",function(token) {
|
||||||
|
return when.resolve("tokens-"+token);
|
||||||
|
});
|
||||||
|
var userTokenHeader = sinon.stub(Users,"tokenHeader",function(token) {
|
||||||
|
return "authorization";
|
||||||
|
});
|
||||||
|
strategies.tokensStrategy._success = strategies.tokensStrategy.success;
|
||||||
|
strategies.tokensStrategy.success = function(user) {
|
||||||
|
user.should.equal("tokens-1234");
|
||||||
|
strategies.tokensStrategy.success = strategies.tokensStrategy._success;
|
||||||
|
delete strategies.tokensStrategy._success;
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
strategies.tokensStrategy.authenticate({headers:{"authorization":"Bearer 1234"}});
|
||||||
|
});
|
||||||
|
it('Fails if tokens user not enabled',function(done) {
|
||||||
|
var userTokens = sinon.stub(Users,"tokens",function() {
|
||||||
|
return when.resolve(null);
|
||||||
|
});
|
||||||
|
var userTokenHeader = sinon.stub(Users,"tokenHeader",function(token) {
|
||||||
|
return "authorization";
|
||||||
|
});
|
||||||
|
strategies.tokensStrategy._fail = strategies.tokensStrategy.fail;
|
||||||
|
strategies.tokensStrategy.fail = function(err) {
|
||||||
|
err.should.equal(401);
|
||||||
|
strategies.tokensStrategy.fail = strategies.tokensStrategy._fail;
|
||||||
|
delete strategies.tokensStrategy._fail;
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
strategies.tokensStrategy.authenticate({headers:{"authorization":"Bearer 1234"}});
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
Users.tokens.restore();
|
||||||
|
Users.tokenHeader.restore();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
describe("Bearer Strategy", function() {
|
describe("Bearer Strategy", function() {
|
||||||
it('Rejects invalid token',function(done) {
|
it('Rejects invalid token',function(done) {
|
||||||
var getToken = sinon.stub(Tokens,"get",function(token) {
|
var getToken = sinon.stub(Tokens,"get",function(token) {
|
||||||
|
@ -227,4 +227,47 @@ describe("api/auth/users", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Initialised with tokens set as function',function() {
|
||||||
|
before(function() {
|
||||||
|
Users.init({
|
||||||
|
type:"strategy",
|
||||||
|
tokens: function(token) { return("Done-"+token); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
after(function() {
|
||||||
|
Users.init({});
|
||||||
|
});
|
||||||
|
describe('#tokens',function() {
|
||||||
|
it('handles api.tokens being a function',function(done) {
|
||||||
|
Users.should.have.property('tokens').which.is.a.Function();
|
||||||
|
(Users.tokens("1234")).should.equal("Done-1234");
|
||||||
|
(Users.tokenHeader()).should.equal("authorization");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Initialised with tokens set as function and tokenHeader set as token header name',function() {
|
||||||
|
before(function() {
|
||||||
|
Users.init({
|
||||||
|
type:"strategy",
|
||||||
|
tokens: function(token) { return("Done-"+token); },
|
||||||
|
tokenHeader: "X-TEST-TOKEN"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
after(function() {
|
||||||
|
Users.init({});
|
||||||
|
});
|
||||||
|
describe('#tokens',function() {
|
||||||
|
it('handles api.tokens being a function and api.tokenHeader being a header name',function(done) {
|
||||||
|
Users.should.have.property('tokens').which.is.a.Function();
|
||||||
|
(Users.tokens("1234")).should.equal("Done-1234");
|
||||||
|
Users.should.have.property('tokenHeader').which.is.a.Function();
|
||||||
|
(Users.tokenHeader()).should.equal("x-test-token");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user