Is it possible to apply basic authentication / middleware in on routes with a whitelist in Express? - node.js

I'm implementing a RESTful API with Express in Node, and I'm new to both. I'd like to use basic authentication to control access.
I would like to apply it using something like a whitelist but I'm not sure how to do that.
Blacklisting is easy, I can just pepper my #VERB calls with the second argument:
app.get('/', asyncAuth, requestHandler);
I can take that even further and blacklist everything with:
app.all('*', asyncAuth, requestHandler);
But I want to apply my basicAuth to every single route, except for POST /users. Is there an elegant way to do that? Can I use the 'blacklist' approach then selectively remove it from the routes I'd like? I couldn't figure out how.

Define your route for POST /users before the blacklisted routes:
app.post('/users', function(req, res) {
...
});
app.all('*', asyncAuth, requestHandler);

You could maintain a list of regexps that are whitelisted, and match the url against each url in the list, if it matches any then proceed, else require auth
app.all('*', asyncAuth);
function asyncAuth(req, res, next) {
var done = false;
whitelist.forEach(function(regexp) {
if (req.url.match(regexp)) {
done = true;
next();
}
});
if (!done) requireAuth(next);
}
Something along those lines

Related

How to use only PART of the functionality in nested routes NodeJS

So I have a router schoolsRouter where all the school-specific functionality is being handled { login school, adding a new teacher, ...etc.). And I want the admin of the app to be able to add and delete new schools. Now the pattern I'm using encapsulates all the routing functionality in one file schools.routes.js where the School model is exposed. So the createSchool and deleteSchool routes are in the schools.routes.js but I need only the admin to be able to perform those operations and that seems pretty easy with merged routes like this (in admins.routes.js):
adminsRouter.use('/schools/', schoolsRouter);
but the problem is that now the admin can access all the other routes in schools.routes.js like schools/login which is something that I don't want to happen. So how can I make the adminsRouter use the create and delete operations from the schoolsRotuer without being able to access all these other functionalities? (Keeping in mind I'm using JWT authentication).
You could use middlewares in the routes that you wish to controll.
This is the middleware that I will name of admin-middleware.js
module.exports = (req, res, next) => {
if (user.admin === true) {
return next();
} else {
return res.status(403).send('Unauthorized')
}
}
So, this is your route declaration at schools.routes.js
const adminMiddleware = require('../YOUR_FOLDERS/admin-middleware.js');
schools.delete('/:id', adminMiddleware, (req, res) => {
return res.send('ok');
});
If you wish disregard a route, you can use this validation at your code in the middleware.
if(req.originalUrl.includes('/schools/login'))
return next();
I hope that it works to you.

ExpressJS - Middleware Too Many Redirects

I am trying to use two middleware with my /app routes that checks for user authentication and then the status of their account. I have both middleware in place, but I am running into an endless redirect in instances where my req.session.accountStatus does not equal the conditions I have provided it. In general, I am trying to force the user to only have access to the page being redirected to. Am I using middleware in the wrong way? Is there a better approach?
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()){
return next();
}
res.redirect('/login');
}
function accountStatus(req, res, next) {
if(req.session.accountStatus == "active" || req.session.accountStatus == "trialing"){
return next();
} else {
//Endless loop. Need to fix
res.redirect('/app/settings/billing');
}
}
router.use(require('./site-routes'));
router.use('/app', isLoggedIn, accountStatus, require('./app-routes'));
It's probably easier to move the middleware to app-router.js.
So your main file would only do this:
router.use('/app', require('./app-routes'));
In app-routes.js, you first add the route for the URL that should be "open";
router.get('/settings/billing', ...);
Followed by the restrictive middleware:
router.use(isLoggedIn, accountStatus);
Followed by the rest of the routes.
That way, any requests for /app/settings/billing don't get passed through the middleware at all, and won't cause a redirect loop.
If isLoggedIn is mandatory for any route that starts with /app, you can use it in a similar way:
router.use(isLoggedIn);
router.get('/settings/billing', ...);
router.use(accountStatus);
router.get(...);

Common Pre-Handler for ConnectJS/ExpressJS url handlers?

In my ExpressJS app, several of my urls handlers have the following logic:
See if the user has permission to access a resource
If so, continue
Else, redirect to the main handler.
Is there a way to insert a pre-handler for certain url handlers, via ConnectJS or ExpressJS?
I know I can do it globally, for all handlers, (which I do to insert missing headers as a result from IE's broken XDR).
But, can I do this for a subset of handlers?
I do something like this:
lib/auth.js
exports.checkPerm = function(req, res, next){
//do some permission checks
if ( authorized ) {
next();
} else {
res.render('/401');
return;
}
};
app.js
var auth = require('./lib/auth');
...
app.get('/item/:itemid', auth.checkPerm, routes.item.get);
You can stack middleware before your final route handler like the above line has. It has to have same function signature and call next();
If I understand this question correctly, you know about:
// This is too general
app.use(myAuthMiddleware());
And you are aware that you can add it manually to certain url-handlers:
app.get('/user/profile/edit', myAuthMiddleware(), function(req,res){
/* handle stuff */ });
// but doing this on all your routes is too much work.
What you might not know about express' mounting feature:
// Matches everything under /static/** Cool.
app.use('/static', express.static(__dirname + '/public'));
Or app.all():
// requireAuthentication can call next() and let a more specific
// route handle the non-auth "meat" of the request when it's done.
app.all('/api/*', requireAuthentication);

NodeJS + Express: How to secure a URL

I am using latest versions of NodeJS and ExpressJS (for MVC).
I usually configure my rest paths like this, for example:
app.get('/archive', routes.archive);
Now i want my /admin/* set of URLs to be secured, I mean I need just simple authentication, it's just a draft.
When a user tries to access, for example, /admin/posts, before sending him the corresponding view and data, I check for a req.session.authenticated. If it's not defined, I redirect to the login page.
Login page has a simple validation form, and a sign-in controller method: if user does send "right user" and "right password" I set the session variable and he's authenticated.
What I find difficult, or I don't understand, is how to actually make the "filter" code, I mean, the auth check, before every /admin/* path call.
Does this have something to do with "middleware" express functions?
Thank you
Yep, middleware is exactly what you want. A middleware function is just a function that works just like any other Express route handler, expept it gets run before your actual route handler. You could, for example, do something like this:
function requireLogin(req, res, next) {
if (req.session.loggedIn) {
next(); // allow the next route to run
} else {
// require the user to log in
res.redirect("/login"); // or render a form, etc.
}
}
// Automatically apply the `requireLogin` middleware to all
// routes starting with `/admin`
app.all("/admin/*", requireLogin, function(req, res, next) {
next(); // if the middleware allowed us to get here,
// just move on to the next route handler
});
app.get("/admin/posts", function(req, res) {
// if we got here, the `app.all` call above has already
// ensured that the user is logged in
});
You could specify requireLogin as a middleware to each of the routes you want to be protected, instead of using the app.all call with /admin/*, but doing it the way I show here ensures that you can't accidentally forget to add it to any page that starts with /admin.
A even simpler approach would be to add the following code in the App.js file.
var auth = function(req, res, next) {
if(isAdmin) {
return next();
} else {
return res.status(400)
}
};
app.use('/admin', auth, apiDecrement);
As you can see the middleware is being attached to the route. Before ExpressJS goes forward, it executes the function that you passed as the second parameter.
With this solution you can make different checks before displaying the site to the end user.
Best.
Like brandon, but you can also go the connect route
app.use('/admin', requireLogin)
app.use(app.router)
app.get('/admin/posts', /* middleware */)

Routing Engine for Node.js

I'm getting into Node.JS and would like to have flexibility on the routing engine. I want control over the mapping between urls comming and and what methods get fired.
I'd really like to setup placeholders in the route matching to automatically parse parameters too. Something like
{"routes": [
{'route': {'url': '/path/to/resource/[id]'}, "handler": idHandler()},
{'route': {'url': '/path/to/foo/[category]/bar'}, "handler": fooHandler(),
{'route': {'url': '/path/to/resource/'}, "handler": defaultHandler()}}
]};
You can choose a more specific solution (just for routing) like Director, or if you don't want to handle cookies, sessions, redirect functions etc your best option is Express.js or Flatiron (which you can use with Director).
I'll paste the code from the two so you can see how they can help in routing:
Express
app.get('/', function(req, res){
res.send('index page');
});
app.post('/login', function(req, res) {
// login logic
});
Director
//
// define a routing table.
//
var router = new director.http.Router({
'/hello': {
get: helloWorld
}
});
//
// You can also do ad-hoc routing, similar to `journey` or `express`.
// This can be done with a string or a regexp.
//
router.get('/bonjour', helloWorld);
router.get(/hola/, helloWorld);
Resources:
http://expressjs.com/en/guide/routing.html
http://blog.nodejitsu.com/scaling-isomorphic-javascript-code
http://blog.nodejitsu.com/introducing-flatiron
http://howtonode.org/express-mongodb
Yes, Express will be your best option, I think. No need to "re-invent the wheel" so to speak. You can do RegEx's on routes as well, which gives you a ton of flexibility. I suggest reading up on the guide...it has a lot of good info!
http://expressjs.com/en/guide/routing.html
Express.js and Connect have great support for routing, vhosts and a large number of extensions are available out there. For example simple integration of jade template rendering or less stylesheet processing.
Define routes with parameters, regular expressions and different HTTP methods.
app.get('/home', function(req, res) { });
app.post('/save/:contactID', function(req, res) { });
app.all('/params/:required/:andOptional?', function(req, res) { });
See kickstart and kickstart-example for an example of express with enabled jade and less processing.

Resources