mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
parent
32163d5f21
commit
1df2f5e96a
@ -123,15 +123,16 @@ 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;
|
||||
|
||||
function authenticateUserToken(req) {
|
||||
return new Promise( (resolve,reject) => {
|
||||
var token = null;
|
||||
if (Users.tokenHeader() === 'authorization') {
|
||||
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];
|
||||
}
|
||||
@ -139,22 +140,40 @@ TokensStrategy.prototype.authenticate = function(req) {
|
||||
token = req.headers[Users.tokenHeader()];
|
||||
}
|
||||
if (token) {
|
||||
Users.tokens(token).then(function(admin) {
|
||||
if (admin) {
|
||||
self.success(admin,{scope:admin.permissions});
|
||||
Users.tokens(token).then(function(user) {
|
||||
if (user) {
|
||||
resolve(user);
|
||||
} else {
|
||||
self.fail(401);
|
||||
reject();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.fail(401);
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function TokensStrategy() {
|
||||
passport.Strategy.call(this);
|
||||
this.name = 'tokens';
|
||||
}
|
||||
util.inherits(TokensStrategy, passport.Strategy);
|
||||
TokensStrategy.prototype.authenticate = function(req) {
|
||||
authenticateUserToken(req).then(user => {
|
||||
this.success(user,{scope:user.permissions});
|
||||
}).catch(err => {
|
||||
this.fail(401);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
bearerStrategy: bearerStrategy,
|
||||
clientPasswordStrategy: clientPasswordStrategy,
|
||||
passwordTokenExchange: passwordTokenExchange,
|
||||
anonymousStrategy: new AnonymousStrategy(),
|
||||
tokensStrategy: new TokensStrategy()
|
||||
tokensStrategy: new TokensStrategy(),
|
||||
authenticateUserToken: authenticateUserToken
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ var api = {
|
||||
authenticate: authenticate,
|
||||
default: getDefaultUser,
|
||||
tokens: getDefaultUser,
|
||||
tokenHeader: "authorization"
|
||||
tokenHeader: null
|
||||
}
|
||||
|
||||
function init(config) {
|
||||
@ -111,6 +111,8 @@ function init(config) {
|
||||
api.tokens = config.tokens;
|
||||
if (config.tokenHeader && typeof config.tokenHeader === "string") {
|
||||
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 Users;
|
||||
var Permissions;
|
||||
var Strategies;
|
||||
|
||||
var server;
|
||||
var settings;
|
||||
@ -44,6 +45,7 @@ function init(_server,_settings,_runtimeAPI) {
|
||||
Tokens.onSessionExpiry(handleSessionExpiry);
|
||||
Users = require("../auth/users");
|
||||
Permissions = require("../auth/permissions");
|
||||
Strategies = require("../auth/strategies");
|
||||
|
||||
}
|
||||
function handleSessionExpiry(session) {
|
||||
@ -63,17 +65,18 @@ function generateSession(length) {
|
||||
return token.join("");
|
||||
}
|
||||
|
||||
function CommsConnection(ws) {
|
||||
function CommsConnection(ws, user) {
|
||||
this.session = generateSession(32);
|
||||
this.ws = ws;
|
||||
this.stack = [];
|
||||
this.user = null;
|
||||
this.user = user;
|
||||
this.lastSentTime = 0;
|
||||
var self = this;
|
||||
|
||||
log.audit({event: "comms.open"});
|
||||
log.trace("comms.open "+self.session);
|
||||
var pendingAuth = (settings.adminAuth != null);
|
||||
var preAuthed = !!user;
|
||||
var pendingAuth = !this.user && (settings.adminAuth != null);
|
||||
|
||||
if (!pendingAuth) {
|
||||
addActiveConnection(self);
|
||||
@ -199,8 +202,8 @@ function start() {
|
||||
var commsPath = settings.httpAdminRoot || "/";
|
||||
commsPath = (commsPath.slice(0,1) != "/" ? "/":"") + commsPath + (commsPath.slice(-1) == "/" ? "":"/") + "comms";
|
||||
wsServer = new ws.Server({ noServer: true });
|
||||
wsServer.on('connection',function(ws) {
|
||||
var commsConnection = new CommsConnection(ws);
|
||||
wsServer.on('connection',function(ws, request, user) {
|
||||
var commsConnection = new CommsConnection(ws, user);
|
||||
});
|
||||
wsServer.on('error', function(err) {
|
||||
log.warn(log._("comms.error-server",{message:err.toString()}));
|
||||
@ -209,8 +212,26 @@ function start() {
|
||||
server.on('upgrade', function upgrade(request, socket, head) {
|
||||
const pathname = url.parse(request.url).pathname;
|
||||
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);
|
||||
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.emit('connection', ws, request, null);
|
||||
});
|
||||
}
|
||||
// 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() {
|
||||
it("returns null for tokenHeader", function() {
|
||||
should.not.exist(Users.tokenHeader());
|
||||
});
|
||||
|
||||
it('delegates get user',function(done) {
|
||||
Users.get('dave').then(function(user) {
|
||||
try {
|
||||
|
Loading…
Reference in New Issue
Block a user