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

Prompt login if auth enabled

This commit is contained in:
Nick O'Leary 2014-11-11 10:15:02 +00:00
parent 2128b57ab2
commit 28823802ea
13 changed files with 249 additions and 136 deletions

View File

@ -39,9 +39,9 @@
<li><a id="btn-sidemenu" class="button" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a></li> <li><a id="btn-sidemenu" class="button" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a></li>
<ul> <ul>
</div> </div>
<div id="main-container" class="sidebar-closed"> <div id="main-container" class="sidebar-closed hide">
<div id="palette"> <div id="palette">
<img src="spin.svg" class="palette-spinner"/> <img src="spin.svg" class="palette-spinner hide"/>
<div id="palette-container" class="palette-scroll"> <div id="palette-container" class="palette-scroll">
</div> </div>
<div id="palette-search"> <div id="palette-search">
@ -80,6 +80,7 @@
<div id="notifications"></div> <div id="notifications"></div>
<div id="dropTarget"><div>Drop the flow here<br/><i class="fa fa-download"></i></div></div> <div id="dropTarget"><div>Drop the flow here<br/><i class="fa fa-download"></i></div></div>
<div id="shade"></div>
<div id="dialog" class="hide"><form id="dialog-form" class="form-horizontal"></form></div> <div id="dialog" class="hide"><form id="dialog-form" class="form-horizontal"></form></div>
<div id="node-config-dialog" class="hide"><form id="dialog-config-form" class="form-horizontal"></form><div class="form-tips" id="node-config-dialog-user-count"></div></div> <div id="node-config-dialog" class="hide"><form id="dialog-config-form" class="form-horizontal"></form><div class="form-tips" id="node-config-dialog-user-count"></div></div>
@ -238,6 +239,14 @@
</div> </div>
</script> </script>
<div id="node-dialog-login" class="hide">
<div style="display: inline-block;width: 250px; vertical-align: top; margin-right: 10px; margin-bottom: 20px;"><img src="node-red-256.png"/></div>
<div style="display: inline-block; width: 250px; vertical-align: bottom; margin-left: 10px; margin-bottom: 20px;">
<form id="node-dialog-login-fields" class="form-horizontal"></form>
</div>
</div>
<script src="jquery/js/jquery-1.11.1.min.js"></script> <script src="jquery/js/jquery-1.11.1.min.js"></script>
<script src="bootstrap/js/bootstrap.min.js"></script> <script src="bootstrap/js/bootstrap.min.js"></script>
<script src="jquery/js/jquery-ui-1.10.3.custom.min.js"></script> <script src="jquery/js/jquery-ui-1.10.3.custom.min.js"></script>

View File

@ -22,34 +22,6 @@ var RED = (function() {
} }
var deploymentType = "full"; var deploymentType = "full";
function hideDropTarget() {
$("#dropTarget").hide();
RED.keyboard.remove(/* ESCAPE */ 27);
}
$('#chart').on("dragenter",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
$("#dropTarget").css({display:'table'});
RED.keyboard.add(/* ESCAPE */ 27,hideDropTarget);
}
});
$('#dropTarget').on("dragover",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
event.preventDefault();
}
})
.on("dragleave",function(event) {
hideDropTarget();
})
.on("drop",function(event) {
var data = event.originalEvent.dataTransfer.getData("text/plain");
hideDropTarget();
RED.view.importNodes(data);
event.preventDefault();
});
function save(force) { function save(force) {
if (RED.view.dirty()) { if (RED.view.dirty()) {
//$("#debug-tab-clear").click(); // uncomment this to auto clear debug on deploy //$("#debug-tab-clear").click(); // uncomment this to auto clear debug on deploy
@ -291,13 +263,13 @@ var RED = (function() {
dialog.modal(); dialog.modal();
} }
function changeDeploymentType(type) { function changeDeploymentType(type) {
deploymentType = type; deploymentType = type;
$("#btn-deploy img").attr("src",deploymentTypes[type].img); $("#btn-deploy img").attr("src",deploymentTypes[type].img);
} }
$(function() { function load() {
RED.settings.init(function() {
RED.menu.init({id:"btn-sidemenu", RED.menu.init({id:"btn-sidemenu",
options: [ options: [
{id:"btn-sidebar",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true}, {id:"btn-sidebar",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true},
@ -348,14 +320,94 @@ var RED = (function() {
] ]
}); });
$("#main-container").show();
$("#btn-deploy").show();
$("#btn-sidemenu").show();
RED.library.init();
RED.palette.init();
RED.sidebar.init();
RED.view.init();
RED.keyboard.add(/* ? */ 191,{shift:true},function(){showHelp();d3.event.preventDefault();}); RED.keyboard.add(/* ? */ 191,{shift:true},function(){showHelp();d3.event.preventDefault();});
loadSettings();
RED.comms.connect(); RED.comms.connect();
loadNodeList();
},
function(err,msg) {
if (err == 401) {
$.ajax({
dataType: "json",
url: "auth/login",
success: function(data) {
if (data.type == "credentials") {
for (var i=0;i<data.prompts.length;i++) {
var field = data.prompts[i];
var row = $("<div/>",{class:"form-row"});
$('<label for="node-dialog-login-'+field.id+'">'+field.label+':</label><br/>').appendTo(row);
$('<input style="width: 100%" id="node-dialog-login-'+field.id+'" type="'+field.type+'"/>').appendTo(row);
row.appendTo("#node-dialog-login-fields");
}
$('<div class="form-row" style="text-align: right"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;" class="hide">Login failed</span><img src="spin.svg" style="height: 30px" class="login-spinner hide"/> <a href="#" id="node-dialog-login-submit">Login</a></div>').appendTo("#node-dialog-login-fields");
$("#node-dialog-login-submit").button().click(function( event ) {
$("#node-dialog-login-submit").button("option","disabled",true);
$("#node-dialog-login-failed").hide();
$(".login-spinner").show();
$.ajax({
url:"auth/token",
type: "POST",
data: {
grant_type: "password",
username: $("#node-dialog-login-username").val(),
password: $("#node-dialog-login-password").val(),
client_id: "node-red-admin",
scope:"*"
}
}).done(function(data,textStatus,xhr) {
$.ajaxSetup({
headers:{"authorization":"bearer "+data.access_token}
}); });
$("#node-dialog-login").dialog("close");
load();
}).fail(function(jqXHR,textStatus,errorThrown) {
$("#node-dialog-login-failed").show();
}).always(function() {
$("#node-dialog-login-submit").button("option","disabled",false);
$(".login-spinner").hide();
});
event.preventDefault();
});
}
}
});
var dialog = $("#node-dialog-login");
dialog.dialog({
autoOpen: false,
dialogClass: "ui-dialog-no-close",
modal: true,
closeOnEscape: false,
width: 600,
resizable: false,
draggable: false,
open: function(event, ui) { console.log("opening");$(".ui-dialog-titlebar", ui.dialog || ui).hide(); }
});
dialog.dialog("open");
}
});
}
$(function() {
if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) { if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) {
document.title = "Node-RED : "+window.location.hostname; document.title = "Node-RED : "+window.location.hostname;
} }
$("#btn-deploy").hide();
$("#btn-sidemenu").hide();
load();
});
return { return {
}; };

View File

@ -66,9 +66,6 @@ RED.library = (function() {
$("#btn-import-library-submenu").replaceWith(menu); $("#btn-import-library-submenu").replaceWith(menu);
}); });
} }
loadFlowLibrary();
function createUI(options) { function createUI(options) {
var libraryData = {}; var libraryData = {};
@ -360,6 +357,9 @@ RED.library = (function() {
} }
return { return {
init: function() {
loadFlowLibrary();
},
create: createUI, create: createUI,
loadFlowLibrary: loadFlowLibrary loadFlowLibrary: loadFlowLibrary
} }

View File

@ -36,8 +36,6 @@ RED.palette = (function() {
}); });
} }
core.forEach(createCategoryContainer);
function setLabel(type, el,label) { function setLabel(type, el,label) {
var nodeWidth = 80; var nodeWidth = 80;
var nodeHeight = 25; var nodeHeight = 25;
@ -241,6 +239,9 @@ RED.palette = (function() {
}); });
} }
function init() {
$(".palette-spinner").show();
core.forEach(createCategoryContainer);
$("#palette-search-input").focus(function(e) { $("#palette-search-input").focus(function(e) {
RED.keyboard.disable(); RED.keyboard.disable();
}); });
@ -265,8 +266,10 @@ RED.palette = (function() {
$("#palette-search-input").blur(); $("#palette-search-input").blur();
}); });
}); });
}
return { return {
init: init,
add:addNodeType, add:addNodeType,
remove:removeNodeType, remove:removeNodeType,
hide:hideNodeType, hide:hideNodeType,

View File

@ -26,6 +26,7 @@ RED.sidebar = (function() {
$("#"+tab.id).remove(); $("#"+tab.id).remove();
} }
}); });
function addTab(title,content,closeable) { function addTab(title,content,closeable) {
$("#sidebar-content").append(content); $("#sidebar-content").append(content);
$(content).hide(); $(content).hide();
@ -129,22 +130,23 @@ RED.sidebar = (function() {
} }
function showSidebar(id) { function showSidebar(id) {
//RED.menu.setSelected("btn-sidebar", true); if (id) {
sidebar_tabs.activateTab("tab-" + id); sidebar_tabs.activateTab("tab-"+id);
}
} }
function containsTab(id) { function containsTab(id) {
return sidebar_tabs.contains("tab-"+id); return sidebar_tabs.contains("tab-"+id);
} }
function init () {
$(function() {
RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("btn-sidebar",!RED.menu.isSelected("btn-sidebar"));d3.event.preventDefault();}); RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("btn-sidebar",!RED.menu.isSelected("btn-sidebar"));d3.event.preventDefault();});
showSidebar("info"); showSidebar();
}); RED.sidebar.info.show();
}
return { return {
init: init,
addTab: addTab, addTab: addTab,
removeTab: removeTab, removeTab: removeTab,
show: showSidebar, show: showSidebar,

View File

@ -32,7 +32,12 @@ RED.sidebar.info = (function() {
content.style.paddingLeft = "4px"; content.style.paddingLeft = "4px";
content.style.paddingRight = "4px"; content.style.paddingRight = "4px";
RED.sidebar.addTab("info",content); function show() {
if (!RED.sidebar.containsTab("info")) {
RED.sidebar.addTab("info",content,false);
}
RED.sidebar.show("info");
}
function jsonFilter(key,value) { function jsonFilter(key,value) {
if (key === "") { if (key === "") {
@ -116,6 +121,7 @@ RED.sidebar.info = (function() {
} }
return { return {
show: show,
refresh:refresh, refresh:refresh,
clear: function() { clear: function() {
$("#tab-info").html(""); $("#tab-info").html("");

View File

@ -365,7 +365,8 @@ RED.view = (function() {
RED.history.push({t:'add',workspaces:[ws],dirty:dirty}); RED.history.push({t:'add',workspaces:[ws],dirty:dirty});
RED.view.dirty(true); RED.view.dirty(true);
} }
$(function() {
function init() {
$('#btn-workspace-add-tab').on("click",addWorkspace); $('#btn-workspace-add-tab').on("click",addWorkspace);
RED.menu.setAction('btn-workspace-add',addWorkspace); RED.menu.setAction('btn-workspace-add',addWorkspace);
@ -375,7 +376,7 @@ RED.view = (function() {
RED.menu.setAction('btn-workspace-delete',function() { RED.menu.setAction('btn-workspace-delete',function() {
deleteWorkspace(activeWorkspace); deleteWorkspace(activeWorkspace);
}); });
}); }
function deleteWorkspace(id) { function deleteWorkspace(id) {
if (workspace_tabs.count() == 1) { if (workspace_tabs.count() == 1) {
@ -2052,7 +2053,35 @@ RED.view = (function() {
}); });
function hideDropTarget() {
$("#dropTarget").hide();
RED.keyboard.remove(/* ESCAPE */ 27);
}
$('#chart').on("dragenter",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
$("#dropTarget").css({display:'table'});
RED.keyboard.add(/* ESCAPE */ 27,hideDropTarget);
}
});
$('#dropTarget').on("dragover",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
event.preventDefault();
}
})
.on("dragleave",function(event) {
hideDropTarget();
})
.on("drop",function(event) {
var data = event.originalEvent.dataTransfer.getData("text/plain");
hideDropTarget();
RED.view.importNodes(data);
event.preventDefault();
});
return { return {
init: init,
state:function(state) { state:function(state) {
if (state == null) { if (state == null) {
return mouse_mode return mouse_mode

15
red.js
View File

@ -121,13 +121,14 @@ settings.flowFile = flowFile || settings.flowFile;
RED.init(server,settings); RED.init(server,settings);
if (settings.httpAdminRoot !== false && settings.httpAdminAuth) { //if (settings.httpAdminRoot !== false && settings.httpAdminAuth) {
app.use(settings.httpAdminRoot, // app.use(settings.httpAdminRoot,
express.basicAuth(function(user, pass) { // express.basicAuth(function(user, pass) {
return user === settings.httpAdminAuth.user && crypto.createHash('md5').update(pass,'utf8').digest('hex') === settings.httpAdminAuth.pass; // return user === settings.httpAdminAuth.user && crypto.createHash('md5').update(pass,'utf8').digest('hex') === settings.httpAdminAuth.pass;
}) // })
); // );
} //}
if (settings.httpNodeRoot !== false && settings.httpNodeAuth) { if (settings.httpNodeRoot !== false && settings.httpNodeAuth) {
app.use(settings.httpNodeRoot, app.use(settings.httpNodeRoot,
express.basicAuth(function(user, pass) { express.basicAuth(function(user, pass) {

View File

@ -53,11 +53,20 @@ function getToken(req,res,next) {
return server.token()(req,res,next); return server.token()(req,res,next);
} }
function login(req,res) {
var response = {
"type":"credentials",
"prompts":[{id:"username",type:"text",label:"Username"},{id:"password",type:"password",label:"Password"}]
}
res.json(response);
}
module.exports = { module.exports = {
authenticate: authenticate, authenticate: authenticate,
ensureClientSecret: ensureClientSecret, ensureClientSecret: ensureClientSecret,
authenticateClient: authenticateClient, authenticateClient: authenticateClient,
getToken: getToken, getToken: getToken,
errorHandler: server.errorHandler() errorHandler: server.errorHandler(),
login: login
} }

View File

@ -29,7 +29,7 @@ var bearerStrategy = function (accessToken, done) {
if (token) { if (token) {
users.get(token.user).then(function(user) { users.get(token.user).then(function(user) {
if (user) { if (user) {
done(null,user,{scope:token.scope}); done(null,{username:user.username},{scope:token.scope});
} else { } else {
done(null,false); done(null,false);
} }

View File

@ -50,6 +50,7 @@ function init(adminApp) {
auth.getToken, auth.getToken,
auth.errorHandler auth.errorHandler
); );
apiApp.get("/auth/login",auth.login);
// Flows // Flows
apiApp.get("/flows",flows.get); apiApp.get("/flows",flows.get);

View File

@ -19,7 +19,8 @@ module.exports = {
settings: function(req,res) { settings: function(req,res) {
var safeSettings = { var safeSettings = {
httpNodeRoot: settings.httpNodeRoot, httpNodeRoot: settings.httpNodeRoot,
version: settings.version version: settings.version,
user: req.user
}; };
res.json(safeSettings); res.json(safeSettings);
} }

View File

@ -66,7 +66,7 @@ module.exports = {
// You can protect the user interface with a userid and password by using the following property. // You can protect the user interface with a userid and password by using the following property.
// The password must be an md5 hash eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password') // The password must be an md5 hash eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
//httpAdminAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"}, httpAdminAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"},
// Some nodes, such as HTTP In, can be used to listen for incoming http requests. // Some nodes, such as HTTP In, can be used to listen for incoming http requests.
// By default, these are served relative to '/'. The following property // By default, these are served relative to '/'. The following property