mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
parent
32163d5f21
commit
1df2f5e96a
@ -123,38 +123,57 @@ AnonymousStrategy.prototype.authenticate = function(req) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function authenticateUserToken(req) {
|
||||||
|
return new Promise( (resolve,reject) => {
|
||||||
|
var token = null;
|
||||||
|
var tokenHeader = Users.tokenHeader();
|
||||||
|
if (Users.tokenHeader() === null) {
|
||||||
|
// No custom user token provided. Fail the request
|
||||||
|
reject();
|
||||||
|
return;
|
||||||
|
} else 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(user) {
|
||||||
|
if (user) {
|
||||||
|
resolve(user);
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function TokensStrategy() {
|
function TokensStrategy() {
|
||||||
passport.Strategy.call(this);
|
passport.Strategy.call(this);
|
||||||
this.name = 'tokens';
|
this.name = 'tokens';
|
||||||
}
|
}
|
||||||
util.inherits(TokensStrategy, passport.Strategy);
|
util.inherits(TokensStrategy, passport.Strategy);
|
||||||
TokensStrategy.prototype.authenticate = function(req) {
|
TokensStrategy.prototype.authenticate = function(req) {
|
||||||
var self = this;
|
authenticateUserToken(req).then(user => {
|
||||||
var token = null;
|
this.success(user,{scope:user.permissions});
|
||||||
if (Users.tokenHeader() === 'authorization') {
|
}).catch(err => {
|
||||||
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
|
this.fail(401);
|
||||||
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()
|
tokensStrategy: new TokensStrategy(),
|
||||||
|
authenticateUserToken: authenticateUserToken
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ var api = {
|
|||||||
authenticate: authenticate,
|
authenticate: authenticate,
|
||||||
default: getDefaultUser,
|
default: getDefaultUser,
|
||||||
tokens: getDefaultUser,
|
tokens: getDefaultUser,
|
||||||
tokenHeader: "authorization"
|
tokenHeader: null
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(config) {
|
function init(config) {
|
||||||
@ -111,6 +111,8 @@ function init(config) {
|
|||||||
api.tokens = config.tokens;
|
api.tokens = config.tokens;
|
||||||
if (config.tokenHeader && typeof config.tokenHeader === "string") {
|
if (config.tokenHeader && typeof config.tokenHeader === "string") {
|
||||||
api.tokenHeader = config.tokenHeader.toLowerCase();
|
api.tokenHeader = config.tokenHeader.toLowerCase();
|
||||||
|
} else {
|
||||||
|
api.tokenHeader = "authorization";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ var log = require("@node-red/util").log; // TODO: separate module
|
|||||||
var Tokens;
|
var Tokens;
|
||||||
var Users;
|
var Users;
|
||||||
var Permissions;
|
var Permissions;
|
||||||
|
var Strategies;
|
||||||
|
|
||||||
var server;
|
var server;
|
||||||
var settings;
|
var settings;
|
||||||
@ -44,6 +45,7 @@ function init(_server,_settings,_runtimeAPI) {
|
|||||||
Tokens.onSessionExpiry(handleSessionExpiry);
|
Tokens.onSessionExpiry(handleSessionExpiry);
|
||||||
Users = require("../auth/users");
|
Users = require("../auth/users");
|
||||||
Permissions = require("../auth/permissions");
|
Permissions = require("../auth/permissions");
|
||||||
|
Strategies = require("../auth/strategies");
|
||||||
|
|
||||||
}
|
}
|
||||||
function handleSessionExpiry(session) {
|
function handleSessionExpiry(session) {
|
||||||
@ -63,17 +65,18 @@ function generateSession(length) {
|
|||||||
return token.join("");
|
return token.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function CommsConnection(ws) {
|
function CommsConnection(ws, user) {
|
||||||
this.session = generateSession(32);
|
this.session = generateSession(32);
|
||||||
this.ws = ws;
|
this.ws = ws;
|
||||||
this.stack = [];
|
this.stack = [];
|
||||||
this.user = null;
|
this.user = user;
|
||||||
this.lastSentTime = 0;
|
this.lastSentTime = 0;
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
log.audit({event: "comms.open"});
|
log.audit({event: "comms.open"});
|
||||||
log.trace("comms.open "+self.session);
|
log.trace("comms.open "+self.session);
|
||||||
var pendingAuth = (settings.adminAuth != null);
|
var preAuthed = !!user;
|
||||||
|
var pendingAuth = !this.user && (settings.adminAuth != null);
|
||||||
|
|
||||||
if (!pendingAuth) {
|
if (!pendingAuth) {
|
||||||
addActiveConnection(self);
|
addActiveConnection(self);
|
||||||
@ -199,8 +202,8 @@ function start() {
|
|||||||
var commsPath = settings.httpAdminRoot || "/";
|
var commsPath = settings.httpAdminRoot || "/";
|
||||||
commsPath = (commsPath.slice(0,1) != "/" ? "/":"") + commsPath + (commsPath.slice(-1) == "/" ? "":"/") + "comms";
|
commsPath = (commsPath.slice(0,1) != "/" ? "/":"") + commsPath + (commsPath.slice(-1) == "/" ? "":"/") + "comms";
|
||||||
wsServer = new ws.Server({ noServer: true });
|
wsServer = new ws.Server({ noServer: true });
|
||||||
wsServer.on('connection',function(ws) {
|
wsServer.on('connection',function(ws, request, user) {
|
||||||
var commsConnection = new CommsConnection(ws);
|
var commsConnection = new CommsConnection(ws, user);
|
||||||
});
|
});
|
||||||
wsServer.on('error', function(err) {
|
wsServer.on('error', function(err) {
|
||||||
log.warn(log._("comms.error-server",{message:err.toString()}));
|
log.warn(log._("comms.error-server",{message:err.toString()}));
|
||||||
@ -209,8 +212,26 @@ function start() {
|
|||||||
server.on('upgrade', function upgrade(request, socket, head) {
|
server.on('upgrade', function upgrade(request, socket, head) {
|
||||||
const pathname = url.parse(request.url).pathname;
|
const pathname = url.parse(request.url).pathname;
|
||||||
if (pathname === commsPath) {
|
if (pathname === commsPath) {
|
||||||
|
if (Users.tokenHeader() !== null && request.headers[Users.tokenHeader()]) {
|
||||||
|
// The user has provided custom token handling. For the websocket,
|
||||||
|
// the token could be provided in two ways:
|
||||||
|
// - as an http header (only possible with a reverse proxy setup)
|
||||||
|
// - passed over the connected websock in an auth packet
|
||||||
|
// If the header is present, verify the token. If not, use the auth
|
||||||
|
// packet over the connected socket
|
||||||
|
//
|
||||||
|
Strategies.authenticateUserToken(request).then(user => {
|
||||||
|
wsServer.handleUpgrade(request, socket, head, function done(ws) {
|
||||||
|
wsServer.emit('connection', ws, request, user);
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
log.audit({event: "comms.auth.fail"});
|
||||||
|
socket.destroy();
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
wsServer.handleUpgrade(request, socket, head, function done(ws) {
|
wsServer.handleUpgrade(request, socket, head, function done(ws) {
|
||||||
wsServer.emit('connection', ws, request);
|
wsServer.emit('connection', ws, request, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Don't destroy the socket as other listeners may want to handle the
|
// Don't destroy the socket as other listeners may want to handle the
|
||||||
|
@ -155,6 +155,10 @@ describe("api/auth/users", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('#get',function() {
|
describe('#get',function() {
|
||||||
|
it("returns null for tokenHeader", function() {
|
||||||
|
should.not.exist(Users.tokenHeader());
|
||||||
|
});
|
||||||
|
|
||||||
it('delegates get user',function(done) {
|
it('delegates get user',function(done) {
|
||||||
Users.get('dave').then(function(user) {
|
Users.get('dave').then(function(user) {
|
||||||
try {
|
try {
|
||||||
|
Loading…
Reference in New Issue
Block a user