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>
<ul>
</div>
<div id="main-container" class="sidebar-closed">
<div id="main-container" class="sidebar-closed hide">
<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>
<div id="palette-search">
@ -80,6 +80,7 @@
<div id="notifications"></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="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>
</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="bootstrap/js/bootstrap.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";
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) {
if (RED.view.dirty()) {
//$("#debug-tab-clear").click(); // uncomment this to auto clear debug on deploy
@ -290,72 +262,152 @@ var RED = (function() {
dialog.modal();
}
function changeDeploymentType(type) {
deploymentType = type;
$("#btn-deploy img").attr("src",deploymentTypes[type].img);
}
function load() {
RED.settings.init(function() {
RED.menu.init({id:"btn-sidemenu",
options: [
{id:"btn-sidebar",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true},
{id:"btn-node-status",label:"Display node status",toggle:true,onselect:toggleStatus, selected: true},
null,
{id:"btn-import-menu",label:"Import",options:[
{id:"btn-import-clipboard",label:"Clipboard",onselect:RED.view.showImportNodesDialog},
{id:"btn-import-library",label:"Library",options:[]}
]},
{id:"btn-export-menu",label:"Export",disabled:true,options:[
{id:"btn-export-clipboard",label:"Clipboard",disabled:true,onselect:RED.view.showExportNodesDialog},
{id:"btn-export-library",label:"Library",disabled:true,onselect:RED.view.showExportNodesLibraryDialog}
]},
null,
{id:"btn-config-nodes",label:"Configuration nodes",onselect:RED.sidebar.config.show},
null,
{id:"btn-subflow-menu",label:"Subflows", options: [
{id:"btn-create-subflow",label:"Create subflow",onselect:RED.view.createSubflow},
{id:"btn-convert-subflow",label:"Selection to subflow",disabled:true,onselect:RED.view.convertToSubflow},
]},
null,
{id:"btn-workspace-menu",label:"Workspaces",options:[
{id:"btn-workspace-add",label:"Add"},
{id:"btn-workspace-edit",label:"Rename"},
{id:"btn-workspace-delete",label:"Delete"},
null
]},
null,
{id:"btn-keyboard-shortcuts",label:"Keyboard Shortcuts",onselect:showHelp},
{id:"btn-help",label:"Node-RED Website", href:"http://nodered.org/docs"}
]
});
RED.menu.init({id:"btn-deploy-options",
options: [
{id:"btn-deploy-full",toggle:"deploy-type",icon:"images/deploy-full.png",label:"Full",sublabel:"Deploys everything in the workspace",onselect:function(s) { if(s){changeDeploymentType("full")}}},
{id:"btn-deploy-flow",toggle:"deploy-type",icon:"images/deploy-flows.png",label:"Modified Flows",sublabel:"Only deploys flows that contain changed nodes", onselect:function(s) {if(s){changeDeploymentType("flows")}}},
{id:"btn-deploy-node",toggle:"deploy-type",icon:"images/deploy-nodes.png",label:"Modified Nodes",sublabel:"Only deploys nodes that have changed",onselect:function(s) { if(s){changeDeploymentType("nodes")}}}
]
});
RED.menu.init({id:"workspace-subflow-edit-menu",
options: [
{id:"btn-subflow-add-input",label:"Add Input", onselect:function() { }},
{id:"btn-subflow-add-output",label:"Add Output", onselect:function() { }},
{id:"btn-subflow-edit-name",label:"Edit Name", onselect:function() { }},
{id:"btn-subflow-delete",label:"Delete", onselect: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.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() {
RED.menu.init({id:"btn-sidemenu",
options: [
{id:"btn-sidebar",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true},
{id:"btn-node-status",label:"Display node status",toggle:true,onselect:toggleStatus, selected: true},
null,
{id:"btn-import-menu",label:"Import",options:[
{id:"btn-import-clipboard",label:"Clipboard",onselect:RED.view.showImportNodesDialog},
{id:"btn-import-library",label:"Library",options:[]}
]},
{id:"btn-export-menu",label:"Export",disabled:true,options:[
{id:"btn-export-clipboard",label:"Clipboard",disabled:true,onselect:RED.view.showExportNodesDialog},
{id:"btn-export-library",label:"Library",disabled:true,onselect:RED.view.showExportNodesLibraryDialog}
]},
null,
{id:"btn-config-nodes",label:"Configuration nodes",onselect:RED.sidebar.config.show},
null,
{id:"btn-subflow-menu",label:"Subflows", options: [
{id:"btn-create-subflow",label:"Create subflow",onselect:RED.view.createSubflow},
{id:"btn-convert-subflow",label:"Selection to subflow",disabled:true,onselect:RED.view.convertToSubflow},
]},
null,
{id:"btn-workspace-menu",label:"Workspaces",options:[
{id:"btn-workspace-add",label:"Add"},
{id:"btn-workspace-edit",label:"Rename"},
{id:"btn-workspace-delete",label:"Delete"},
null
]},
null,
{id:"btn-keyboard-shortcuts",label:"Keyboard Shortcuts",onselect:showHelp},
{id:"btn-help",label:"Node-RED Website", href:"http://nodered.org/docs"}
]
});
if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) {
document.title = "Node-RED : "+window.location.hostname;
}
$("#btn-deploy").hide();
$("#btn-sidemenu").hide();
RED.menu.init({id:"btn-deploy-options",
options: [
{id:"btn-deploy-full",toggle:"deploy-type",icon:"images/deploy-full.png",label:"Full",sublabel:"Deploys everything in the workspace",onselect:function(s) { if(s){changeDeploymentType("full")}}},
{id:"btn-deploy-flow",toggle:"deploy-type",icon:"images/deploy-flows.png",label:"Modified Flows",sublabel:"Only deploys flows that contain changed nodes", onselect:function(s) {if(s){changeDeploymentType("flows")}}},
{id:"btn-deploy-node",toggle:"deploy-type",icon:"images/deploy-nodes.png",label:"Modified Nodes",sublabel:"Only deploys nodes that have changed",onselect:function(s) { if(s){changeDeploymentType("nodes")}}}
]
});
RED.menu.init({id:"workspace-subflow-edit-menu",
options: [
{id:"btn-subflow-add-input",label:"Add Input", onselect:function() { }},
{id:"btn-subflow-add-output",label:"Add Output", onselect:function() { }},
{id:"btn-subflow-edit-name",label:"Edit Name", onselect:function() { }},
{id:"btn-subflow-delete",label:"Delete", onselect:function() { }},
]
});
RED.keyboard.add(/* ? */ 191,{shift:true},function(){showHelp();d3.event.preventDefault();});
loadSettings();
RED.comms.connect();
load();
});
if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) {
document.title = "Node-RED : "+window.location.hostname;
}
return {
};

View File

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

View File

@ -36,8 +36,6 @@ RED.palette = (function() {
});
}
core.forEach(createCategoryContainer);
function setLabel(type, el,label) {
var nodeWidth = 80;
var nodeHeight = 25;
@ -241,32 +239,37 @@ RED.palette = (function() {
});
}
$("#palette-search-input").focus(function(e) {
RED.keyboard.disable();
});
$("#palette-search-input").blur(function(e) {
RED.keyboard.enable();
});
$("#palette-search-clear").on("click",function(e) {
e.preventDefault();
$("#palette-search-input").val("");
filterChange();
$("#palette-search-input").focus();
});
$("#palette-search-input").val("");
$("#palette-search-input").on("keyup",function() {
filterChange();
});
$("#palette-search-input").on("focus",function() {
$("body").one("mousedown",function() {
$("#palette-search-input").blur();
function init() {
$(".palette-spinner").show();
core.forEach(createCategoryContainer);
$("#palette-search-input").focus(function(e) {
RED.keyboard.disable();
});
});
$("#palette-search-input").blur(function(e) {
RED.keyboard.enable();
});
$("#palette-search-clear").on("click",function(e) {
e.preventDefault();
$("#palette-search-input").val("");
filterChange();
$("#palette-search-input").focus();
});
$("#palette-search-input").val("");
$("#palette-search-input").on("keyup",function() {
filterChange();
});
$("#palette-search-input").on("focus",function() {
$("body").one("mousedown",function() {
$("#palette-search-input").blur();
});
});
}
return {
init: init,
add:addNodeType,
remove:removeNodeType,
hide:hideNodeType,

View File

@ -26,6 +26,7 @@ RED.sidebar = (function() {
$("#"+tab.id).remove();
}
});
function addTab(title,content,closeable) {
$("#sidebar-content").append(content);
$(content).hide();
@ -129,22 +130,23 @@ RED.sidebar = (function() {
}
function showSidebar(id) {
//RED.menu.setSelected("btn-sidebar", true);
sidebar_tabs.activateTab("tab-" + id);
if (id) {
sidebar_tabs.activateTab("tab-"+id);
}
}
function containsTab(id) {
return sidebar_tabs.contains("tab-"+id);
}
$(function() {
function init () {
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 {
init: init,
addTab: addTab,
removeTab: removeTab,
show: showSidebar,

View File

@ -32,8 +32,13 @@ RED.sidebar.info = (function() {
content.style.paddingLeft = "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) {
if (key === "") {
return value;
@ -116,6 +121,7 @@ RED.sidebar.info = (function() {
}
return {
show: show,
refresh:refresh,
clear: function() {
$("#tab-info").html("");

View File

@ -365,7 +365,8 @@ RED.view = (function() {
RED.history.push({t:'add',workspaces:[ws],dirty:dirty});
RED.view.dirty(true);
}
$(function() {
function init() {
$('#btn-workspace-add-tab').on("click",addWorkspace);
RED.menu.setAction('btn-workspace-add',addWorkspace);
@ -375,7 +376,7 @@ RED.view = (function() {
RED.menu.setAction('btn-workspace-delete',function() {
deleteWorkspace(activeWorkspace);
});
});
}
function deleteWorkspace(id) {
if (workspace_tabs.count() == 1) {
@ -2051,8 +2052,36 @@ 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 {
init: init,
state:function(state) {
if (state == null) {
return mouse_mode

15
red.js
View File

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

View File

@ -53,11 +53,20 @@ function getToken(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 = {
authenticate: authenticate,
ensureClientSecret: ensureClientSecret,
authenticateClient: authenticateClient,
getToken: getToken,
errorHandler: server.errorHandler()
errorHandler: server.errorHandler(),
login: login
}

View File

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

View File

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

View File

@ -19,7 +19,8 @@ module.exports = {
settings: function(req,res) {
var safeSettings = {
httpNodeRoot: settings.httpNodeRoot,
version: settings.version
version: settings.version,
user: req.user
};
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.
// 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.
// By default, these are served relative to '/'. The following property