Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added path to JWT cookie #16

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nodes/locales/en-US/users_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"missing-users-config": "Node users config is missing",
"missing-jwt-secret": "JWT secret is not set",
"missing-jwt-cookie-name": "JWT cookie name is not set",
"missing-jwt-cookie-max-age": "JWT cookie max-age is not set",
"missing-users-list": "Node users list is not set"
}
}
Expand Down
28 changes: 21 additions & 7 deletions nodes/users_config.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,7 @@
transition: max-height .2s 0s ease-in-out;
}
.advanced-form-wrapper.expanded {
max-height: 300px;
-moz-transition: max-height .2s 0s ease-in-out;
-webkit-transition: max-height .2s 0s ease-in-out;
transition: max-height .2s 0s ease-in-out;
max-height: 450px;
}
.users-login-link {
overflow-wrap: break-word;
Expand All @@ -127,6 +124,7 @@
name: {value: ""},
appPath: {value: "/users"},
jwtCookieName: {value: ""},
jwtCookieMaxAge: {value: ""},
jwtHttpsOnly: {value: false}
},
credentials: {
Expand All @@ -148,6 +146,7 @@
////////////////////////////////
var SHA512 = new Hashes.SHA512
var DEFAULT_JWT_COOKIE_NAME = "nr.nodeUsers.jwt";
var DEFAULT_JWT_COOKIE_MAX_AGE = '1w';
var DEFAULT_APP_PATH = '/users';

var globalUserConfigNode = null;
Expand Down Expand Up @@ -183,9 +182,12 @@
var appPathLabel = $("<label>", {for: "node-config-input-appPath"}).text("Base URL path").appendTo(appPathForm);
var appPathInput = $("<input>", {type: "text", id: "node-config-input-appPath", "placeholder": "Base URL path (/users)"}).appendTo(appPathForm);

var jwtCookieForm = $("<div>", {class: "form-row"}).appendTo(advancedFormWrapper);
var jwtCookieLabel = $("<label>", {for: "node-config-input-jwtCookieName"}).text("JWT cookie name").appendTo(jwtCookieForm);
var jwtSecretInput = $("<input>", {type: "text", id: "node-config-input-jwtCookieName", "placeholder": "JWT cookie name"}).appendTo(jwtCookieForm);
var jwtCookieRow1 = $("<div>", {class: "form-row"}).appendTo(advancedFormWrapper);
var jwtCookieNameLabel = $("<label>", {for: "node-config-input-jwtCookieName"}).text("JWT cookie name").appendTo(jwtCookieRow1);
var jwtCookieName = $("<input>", {type: "text", id: "node-config-input-jwtCookieName", "placeholder": "JWT cookie name"}).appendTo(jwtCookieRow1);
var jwtCookieRow2 = $("<div>", {class: "form-row"}).appendTo(advancedFormWrapper);
var jwtCookieMaxAgeLabel = $("<label>", {for: "node-config-input-jwtCookieMaxAge"}).text("JWT cookie max-age").appendTo(jwtCookieRow2);
var jwtCookieMaxAge = $("<input>", {type: "text", id: "node-config-input-jwtCookieMaxAge", "placeholder": "e.g. 1y 2M 3w 4d 5h 6m 7s 8ms"}).appendTo(jwtCookieRow2);

var jwtSecretForm = $("<div>", {class: "form-row"}).appendTo(advancedFormWrapper);
var jwtSecretLabel = $("<label>", {for: "node-config-input-jwtSecret"}).text("JWT secret").appendTo(jwtSecretForm);
Expand Down Expand Up @@ -239,6 +241,7 @@
var jwtSecret = $("#node-config-input-jwtSecret").val();
var appPath = $("#node-config-input-appPath").val();
var jwtCookieName = $("#node-config-input-jwtCookieName").val();
var jwtCookieMaxAge = $("#node-config-input-jwtCookieMaxAge").val();
var jwtHttpsOnly = $("#node-config-input-httpsOnly").is(":checked");
var nodeUsers = getNodeUsers();

Expand All @@ -259,6 +262,7 @@
type: "users_config",
appPath: appPath,
jwtCookieName: jwtCookieName,
jwtCookieMaxAge: jwtCookieMaxAge,
jwtHttpsOnly: jwtHttpsOnly,
credentials: {
jwtSecret: jwtSecret,
Expand All @@ -271,6 +275,7 @@
globalUserConfigNode["_def"] = RED.nodes.getType("users_config");
globalUserConfigNode.appPath = appPath;
globalUserConfigNode.jwtCookieName = jwtCookieName;
globalUserConfigNode.jwtCookieMaxAge = jwtCookieMaxAge;
globalUserConfigNode.jwtHttpsOnly = jwtHttpsOnly;
globalUserConfigNode.credentials = {
jwtSecret: jwtSecret,
Expand Down Expand Up @@ -316,6 +321,7 @@
$("#node-config-input-appPath").val(globalUserConfigNode.appPath);
$("#node-config-input-jwtSecret").val(globalUserConfigNode.credentials.jwtSecret);
$("#node-config-input-jwtCookieName").val(globalUserConfigNode.jwtCookieName);
$("#node-config-input-jwtCookieMaxAge").val(globalUserConfigNode.jwtCookieMaxAge);
$("#node-config-input-httpsOnly").prop("checked", globalUserConfigNode.jwtHttpsOnly);

var nodeUsers = globalUserConfigNode.credentials.nodeUsers;
Expand All @@ -328,6 +334,7 @@
} else {
// users config not created, set defaults
$("#node-config-input-jwtCookieName").val(DEFAULT_JWT_COOKIE_NAME);
$("#node-config-input-jwtCookieMaxAge").val(DEFAULT_JWT_COOKIE_MAX_AGE);
$("#node-config-input-appPath").val(DEFAULT_APP_PATH);
$("#node-config-input-jwtSecret").val(generateJwtSecret());
save();
Expand Down Expand Up @@ -437,6 +444,13 @@
save();
});

$(document).on("blur", "#node-config-input-jwtCookieMaxAge", function () {
if ($(this).val() === "") {
$("#node-config-input-jwtCookieMaxAge").val(DEFAULT_JWT_COOKIE_MAX_AGE);
}
save();
});

$(document).on("blur", "#node-config-input-appPath", function () {
if ($(this).val() === "") {
$("#node-config-input-appPath").val(DEFAULT_APP_PATH);
Expand Down
38 changes: 37 additions & 1 deletion nodes/users_config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
var users = require('../users');

function parseDuration(string)
{
const SECONDS = 1000;
const MINUTES = 60 * SECONDS;
const HOURS = 60 * MINUTES;
const DAYS = 24 * HOURS;
const WEEKS = 7 * DAYS;
const MONTHS = 30 * DAYS;
const YEARS = 365 * DAYS;

function intGroup1(match)
{
return match && parseInt(match[1]);
}

function captureField(string, unit)
{
return string && intGroup1(string.match(new RegExp(`\\b(\\d+)${unit}\\b`))) || 0;
}

return (
captureField(string, 'ms') +
captureField(string, 's') * SECONDS +
captureField(string, 'm') * MINUTES +
captureField(string, 'h') * HOURS +
captureField(string, 'd') * DAYS +
captureField(string, 'w') * WEEKS +
captureField(string, 'M') * MONTHS +
captureField(string, 'y') * YEARS
);
}

var DEFAULT_JWT_COOKIE_MAX_AGE = parseDuration('1w');
var DEFAULT_APP_PATH = '/users';

module.exports = function (RED) {

function UsersConfig(n) {
Expand Down Expand Up @@ -29,8 +64,9 @@ module.exports = function (RED) {

node.credentials = credentials;
node.jwtCookieName = n.jwtCookieName;
node.jwtCookieMaxAge = parseDuration(n.jwtCookieMaxAge) || DEFAULT_JWT_COOKIE_MAX_AGE;
node.jwtHttpsOnly = n.jwtHttpsOnly === true;
node.appPath = n.appPath || '/users';
node.appPath = n.appPath || DEFAULT_APP_PATH;
users.init(RED, node);
}

Expand Down
14 changes: 7 additions & 7 deletions users.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ var crypto = require('crypto');
var bodyParser = require('body-parser');

var APP_DIR = path.join(__dirname, './app');
var JWT_COOKIE_EXPIRY = 604800000; // 7 days

var log,
redSettings,
Expand Down Expand Up @@ -34,11 +33,12 @@ function verifyJwt(req) {
}
}

function createJwtToken(req, res, jwtSecret, jwtCookieName, payload) {
var token = jwt.sign(payload, jwtSecret);
res.cookie(jwtCookieName, token, {
maxAge: JWT_COOKIE_EXPIRY,
secure: usersConfig.jwtHttpsOnly === true
function createJwtToken(req, res, payload) {
var token = jwt.sign(payload, usersConfig.credentials.jwtSecret);
res.cookie(usersConfig.jwtCookieName, token, {
maxAge: usersConfig.jwtCookieMaxAge,
secure: usersConfig.jwtHttpsOnly === true,
path: req.baseUrl || '/'
});
}

Expand Down Expand Up @@ -76,7 +76,7 @@ function handleLogin(req, res) {

log.debug('Authenticated node user:'+user.username);

createJwtToken(req, res, usersConfig.credentials.jwtSecret, usersConfig.jwtCookieName, {
createJwtToken(req, res, {
username: user.username,
scope: user.scope
});
Expand Down