Express session with different cookie domain per request? - javascript

I have a situation where an app can be accessed from multiple different domains. For instance, foo.com and bar.com could both in theory point to my app. Additionally, their subdomains can also point to my app, so for instance red.foo.com and blue.foo.com. I'm using Express cookie sessions, and my initialization code for the session looks like that:
app.use(express.session({
secret: "secret",
cookie: {
domain: ".foo.com"
},
store: new MongoStore({
db: db
})
}));
That works well for when users go through foo.com or any of it's subdomains, but bar.com won't work. I need to have both at once. Ideally, I would set it to a different domain per request, but I'm not sure how I would do that. My requests are highly asynchronous and if I just set it for the whole app at every request, I fear it might not work when two calls come in at once.
Is this at all possible? Does anyone have any ideas to solve this?

Here's what you do:
write a middleware your app can use in place of the default express.session middleware
in that middleware, based on the host request header instatiate and configure on instance of the express session middleware per domain, and then actually execute the middleware function appropriate for this request
pseudocode
var mwCache = Object.create(null);
function virtualHostSession(req, res, next) {
var host = req.get('host'); //maybe normalize with toLowerCase etc
var hostSession = mwCache[host];
if (!hostSession) {
hostSession = mwCache[host] = express.session(..config for this host...);
}
hostSession(req, res, next);
//don't need to call next since hostSession will do it for you
}
app.use(virtualHostSession);
My requests are highly asynchronous and if I just set it for the whole app at every request, I fear it might not work when two calls come in at once.
Absolutely you cannot do that. It will be utterly incorrect.

Related

How to use values between various Express routes

I am new to Express and writing an application in node js. I am having problem in using the same parameters. My code is:
app.get('/signin', function (req, res) {
renderView(req, res, 'signin.jade');
});
app.get('/config', function (req, res) {
addOrUpdateGroupConfig(req.query.group_name, req.query.webhook_url);
renderView(req, res, 'config.jade');
});
app.post('/config', function (req, res) {
..
}
function renderView(req, res, view, locals) {
if (locals === undefined) {
locals = {};
}
res.render(view, locals);
}
The sign in jade redirects to app.get(/config) and i am getting webhook_url and group_name. Now I am rendering a config jade page which has form post, after submit the control comes to app.post(/config) now the problem is i want the webhook_url and group_name here to store in database. SO how to pass those values in a good way ?
If the webhook_url and group_name values can't be put into the web page for security reasons, then the usual solution would be to create a session object and store it for that specific user in their session. Then, on the POST, you could get it out of that user's session. The express-session module is available to help you create a session object for each user. This is breaking with the usual stateless design of web pages so there'd have to be a really good reason to go this way.
Otherwise, the value should probably just be inserted into the form in a hidden field (by your renderer) so that when the POST happens, the value will be sent back with the form and you'll have everything you need in the POST data. That keeps your system entirely stateless which is good for a lot of reasons (simplicity, scalability, reliability, etc...).

Rerun routes with new URL

I have a small web server which serves as an optimizer for old URLs, it matches old urls and redirects to new nicer SEO-optimized urls.
One of the url is something like:
login.php?return=http://example.com/index.php?page=protected_page
Now after optimizing the service, http://example.com/index.php?page=protected_page is now just /page/protected_page/ and has the authentication inside, so naturally i put a match like
'login.php': function(req, res, next) {
if (req.query.return) {
res.redirect(req.query.return);
}
}
'index.php': function(req, res, next) {
if (req.query.page === 'protected_page') {
// redirect to proper seo page without index.php
res.redirect(...);
}
}
What will happen in this case, is that first the browser will get redirected to the url in req.query.return, then express will respond to the new request with a match on index.php. This is ok, but if the infrastructure is complicated, it will take some time for client browser to issue a new request (might even be 0.5-1 seconds if the person accessing the website is technically far from the server).
Any way I could take the req.query.return and have something like app.processNewUrl(req.query.return)?

How to go about creating temporary authentication for a website?

I'm new to authentication with websites, and I've been doing a lot of reading on the different kinds of user authentication (for example session vs token authentication) you can use. However, a lot of it seems more than what I need, and I'm not sure which ones will be suitable for my cause.
My idea is to generate temporary user accounts and passwords that will expire after the first use. I want this integrated with my website, so they have one chance to view restricted pages, after which they will not allowed access to those parts again (unless provided with new credentials).
Any direction in the right step will be appreciated.
Update: I'm using Javascript(Node) as my server side language
Session-based authentication is actually incredibly lightweight if you're using a Node backend, due to most (if not all) webserver libraries supporting "middleware", which modify requests before they hit your route functions. The Express-compatable middleware client-sessions is fantastic for this, and I used it previously in a project with great success. It adds a cookie on the first request a user makes to your site which identifies them, and if at some point they log in, you can flag that session as authenticated, store session information, and other data related to them specifically.
Assuming you want both login & logout, the simplest way would to be to use POSTs over HTTPS to login & logout routes. Inside of the resolution for the login route, you would simply "mark for deletion" inside whatever database you're working with.
An example might look like this:
var app = express();
function authenticate(user, pw){
//do your application specific login verification here
}
function deleteAccount(user){
//do your application specific user removal here
}
app.use(require("express-session")({
secret : "YOUR-SECRET-KEY-HERE"
cookieName : "Session"
//any other desired config options go here
})
app.post("/login", function(req, res){
var user = req.body.user;
var pw = req.body.pw;
req.Session.isAuthenticated = authenticate(user, pw)
if(req.Session.isAuthenticated){
markForDeletion(user, pw);
}
res.write("logged in as: " + user);
res.end();
});
app.post("/logout", function(req, res){
deleteAccount(req.Session.username);
req.Session.username = "";
req.Session.isAuthenticated = false;
res.write("logged out!");
res.end();
});

Parse Server Node.js SDK: Alternative to Parse.User.become?

I want to completely dissociate my client app from Parse server, to ease the switch to other Baas/custom backend in the future. As such, all client request will point to a node.js server who will make the request to Parse on behalf of the user.
Client <--> Node.js Server <--> Parse Server
As such, I need the node.js server to be able to switch between users so I can keep the context of their authentification.
I know how to authentificate, then keep the sessionToken of the user, and I ve seen during my research than the "accepted" solution to this problem was to call Parse.User.disableUnsafeCurrentUser, then using Parse.User.become() to switch the current user to the one making a request.
But that feels hackish, and I m pretty sure it will, sooner or later, lead to a race condition where the current user is switched before the request is made to Parse.
Another solution I found was to not care about Parse.User, and use the masterKey to save everything by the server, but that would make the server responsible of the ACL.
Is there a way to make request from different user other than thoses two?
Any request to the backend (query.find(), object.save(), etc) takes an optional options parameter as the final argument. This lets you specify extra permissions levels, such as forcing the master key or using a specific session token.
If you have the session token, your server code can make a request on behalf of that user, preserving ACL permissions.
Let's assume you have a table of Item objects, where we rely on ACLs to ensure that a user can only retrieve his own Items. The following code would use an explicit session token and only return the Items the user can see:
// fetch items visible to the user associate with `token`
fetchItems(token) {
new Parse.Query('Item')
.find({ sessionToken: token })
.then((results) => {
// do something with the items
});
}
become() was really designed for the Parse Cloud Code environment, where each request lives in a sandbox, and you can rely on a global current user for each request. It doesn't really make sense in a Node.js app, and we'll probably deprecate it.
I recently wrote a NodeJS application and had the same problem. I found that the combination of Parse.User.disableUnsafeCurrentUser and Parse.User.become() was not only hackish, but also caused several other problems I wasn't able to anticipate.
So here's what I did: I used
Parse.Cloud.useMasterKey(); and then loaded the current user by session ID as if it was a regular user object. It looked something like this:
module.exports = function(req, res, next) {
var Parse = req.app.locals.parse, query;
res.locals.parse = Parse;
if (req.session.userid === undefined) {
res.locals.user = undefined;
return next();
}
Parse.Cloud.useMasterKey();
query = new Parse.Query(Parse.User);
query.equalTo("objectId", req.session.userid);
query.first().then(function(result) {
res.locals.user = result;
return next();
}, function(err) {
res.locals.user = undefined;
console.error("error recovering user " + req.session.userid);
return next();
});
};
This code can obviously be optimized, but you can see the general idea. Upside: It works! Downside: No more use of Parse.User.current(), and the need to take special care in the backend that no conditions occur where someone overwrites data without permission.

What are the possible ways to authorize a websocket connection request in Express.io?

I have encountered two possibilities and would prefer a solution that performs the check prior to fully establishing the websocket.
var express = require("express.io");
var app = express().http().io();
app.use(express.json());
app.use(express.cookieParser());
app.use(express.session({secret: process.env.COOKIESECRET}));
Option 1: How to get the Express session object?
UPDATE: This might not be workable as Express.io registers its own "authorize" function which makes the Express session available to Socket.io.
app.io.configure(function() {
app.io.set("authorize", function(handshake, authorize) {
// Cookie is available...?
//handshake.headers.cookie
});
});
Option 2: Easy to get Express session, but connection already established.
app.io.route("test", function(req) {
if(!req.session.IsAuthorized) {
req.io.disconnect();
}
});
You can pass in a reference to your sessionstore so it is available when you configure your socket server:
var sessionStore = new express.session.MemoryStore();
app.use(express.session({secret: process.env.COOKIESECRET, store: sessionStore}));
I think you should be able to get the rest from there by matching the handshake.headers object to stuff in your session store. Note that the default store is held in memory, which is not great for production purposes (but fine for now I guess). The above relates to your option 1 method.

Categories

Resources