I have a working node.js restify server configured to work as a static webserver. Here is the relevant code;
var server = restify.createServer({
name: 'myapp',
version: '1.0.0'
});
var static_webserver = function (app) {
app.get(/.*/, restify.serveStatic({
'directory': 'static', //static html files stored in ../static folder
'default': 'index.html'
}));
} //var static_server = function (app)
static_webserver(server);
After I enable HTTP Basic authentication to have better security for the other REST APIs, the static webserver stopped working.
This is the code for enabling HTTP Basic authentication.
server.use(restify.authorizationParser());
function verifyAuthorizedUser(req, res, next)
{
var users;
users = {
foo: {
id: 1,
password: 'bar'
}
};
if (req.username == 'anonymous' || !users[req.username] || req.authorization.basic.password !== users[req.username].password) {
// Respond with { code: 'NotAuthorized', message: '' }
next(new restify.NotAuthorizedError());
} else {
next();
}
next();
}//function verifyAuthorizedUser(req, res, next)
server.use(verifyAuthorizedUser);
It seems that after enabling authentication, no web browser was able to visit the static html webpages because authentication is required. How can I disable authentication for the static webserver but enable authentication for the other REST APIs?
If your nodejs is up to date enough to support string.startsWith():
function verifyAuthorizedUser(req, res, next) {
var path = req.path();
// check if the path starts with /static/
if (path.startsWith('/static/')) {
return next();
}
var users;
users = {
foo: {
id: 1,
password: 'bar'
}
};
if (req.username == 'anonymous' || !users[req.username] || req.authorization.basic.password !== users[req.username].password) {
// Respond with { code: 'NotAuthorized', message: '' }
next(new restify.NotAuthorizedError());
} else {
next();
}
next();
}
If you don't have startsWith(), a good old regex will do:
if (path.match(/\/static\/.*/)) {
return next();
}
Related
Hey I'm using basic auth for Node.JS to secure a route. I'm pretty new to Node.JS and don't understand what the next function does in this case. What I'm trying to do is to secure a the route: /admin/
Note: This is a project for learning purposes so the login part is not too serious and won't be used live.
authentication.js
var basicAuth = require('basic-auth');
exports.BasicAuthentication = function(request, response, next) {
function unauthorized(response) {
response.set('WWW-Authenticate', 'Basic realm=Authorization Required');
return response.send(401);
};
var user = basicAuth(request);
if (!user || !user.name || !user.pass) {
return unauthorized(response);
};
if (user.name === 'name' && user.pass === 'pass') {
return next();
} else {
return unauthorized(response);
};
};
and app.js where I imported the module authentication:
app.get('/admin/', authentication.BasicAuthentication, function(req, res){
console.log("hi u need to login");
});
So what I want to do is to route the user further if the authentication goes through.
Thanks in advance!
Try:
app.get('/admin/', authentication.BasicAuthentication);
app.get('/admin/', function(req, res) {});
This function is known as a middleware:
var basicAuth = require('basic-auth');
exports.BasicAuthentication = function(request, response, next) {
function unauthorized(response) {
response.set('WWW-Authenticate', 'Basic realm=Authorization Required');
return response.send(401);
};
var user = basicAuth(request);
if (!user || !user.name || !user.pass) {
return unauthorized(response);
};
if (user.name === 'name' && user.pass === 'pass') {
return next();
} else {
return unauthorized(response);
};
};
middleware is a function that you can define for various purposes:
using middleware
writing a middleware
In a simple way is a function that runs before performing another action, one general purpose is to protect certain routes for unauthorized access.
You can protect private routes calling then authentication.BasicAuthentication before function(req, res) {}
Some example:
app.get('/user-profile/', authentication.BasicAuthentication, function(req, res){
//private info
});
app.get('/foo/', function(req, res){
//public info
});
I have written a basic policies in Sails js.
in app/config/policies.js
module.exports.policies = {
'*': 'sessionAuth'
};
in app/api/policies/sessionAuth.js
module.exports = function(req, res, next) {
console.log('reach');
if (req.session.authenticated) {
return next();
}
return res.forbidden('You are not permitted to perform this action.');
};
But when i am requesting some URL, 'reach' is not printing in console and this basic policies is not working. It is going to that controller's action which is define in route.js.
The problem is in your policies.js file :
You can try this
module.exports.policies = {
//Your controller
UserController: {
'*': 'sessionAuth'
}
};
I am using node.js restify to build a REST API server.
I have added HTTP Basic authentication to the REST APIs. However, I only want some selected APIs to have authentication. Currently, all the REST APIs have to be authenticated.
Code for enabling HTTP Basic authentication;
server.use(restify.authorizationParser());
function verifyAuthorizedUser(req, res, next)
{
var users;
users = {
foo: {
id: 1,
password: 'bar'
}
};
if (req.username == 'anonymous' || !users[req.username] || req.authorization.basic.password !== users[req.username].password) {
// Respond with { code: 'NotAuthorized', message: '' }
next(new restify.NotAuthorizedError());
} else {
next();
}
next();
}//function verifyAuthorizedUser(req, res, next)
server.use(verifyAuthorizedUser);
Here are some of the APIs I have;
var api_get_XXX = function (app) {
function respond(req, res, next) {
//action
};
// Routes
app.get('/XXX', respond);
}
var api_get_YYY = function (app) {
function respond(req, res, next) {
//action
};
// Routes
app.get('/YYY', respond);
}
var api_get_ZZZ = function (app) {
function respond(req, res, next) {
//action
};
// Routes
app.get('/ZZZ', respond);
}
api_get_XXX(server);
api_get_YYY(server);
api_get_ZZZ(server);
I would like to enable authentication for api_get_XXX(), api_get_YYY() but disable authentication for api_get_ZZZ().
You could maintain an array/object containing the exceptions:
function verifyAuthorizedUser(req, res, next) {
// list your public paths here, you should store this in global scope
var publicPaths = {
'/ZZZ': 1
};
// check them here and skip authentication when it's public
if (publicPaths[req.path()]) {
return next();
}
var users;
users = {
foo: {
id: 1,
password: 'bar'
}
};
if (req.username == 'anonymous' || !users[req.username] || req.authorization.basic.password !== users[req.username].password) {
// Respond with { code: 'NotAuthorized', message: '' }
next(new restify.NotAuthorizedError());
} else {
next();
}
next();
}
Or you can use an existing middleware for authentication: https://github.com/amrav/restify-jwt
I am trying to get a https loopback server up and running protected by OAuth. I am using the loopback gateway sample project as a reference. But for some reason I can't get the OAuth piece to work. What I mean is, even after adding in the OAuth bits and pieces, the APIs don't seem to be protected. I get a response back even if there is no token in my request. This is what my server.js looks like
var loopback = require('loopback');
var boot = require('loopback-boot');
var https = require('https');
var path = require('path');
var httpsRedirect = require('./middleware/https-redirect');
var site = require('./site');
var sslConfig = require('./ssl-config');
var options = {
key: sslConfig.privateKey,
cert: sslConfig.certificate
};
var app = module.exports = loopback();
// Set up the /favicon.ico
app.middleware('initial', loopback.favicon());
// request pre-processing middleware
app.middleware('initial', loopback.compress());
app.middleware('session', loopback.session({ saveUninitialized: true,
resave: true, secret: 'keyboard cat' }));
// -- Add your pre-processing middleware here --
// boot scripts mount components like REST API
boot(app, __dirname);
// Redirect http requests to https
var httpsPort = app.get('https-port');
app.middleware('routes', httpsRedirect({httpsPort: httpsPort}));
var oauth2 = require('loopback-component-oauth2')(
app, {
// Data source for oAuth2 metadata persistence
dataSource: app.dataSources.pg,
loginPage: '/login', // The login page url
loginPath: '/login' // The login processing url
});
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Set up login/logout forms
app.get('/login', site.loginForm);
app.get('/logout', site.logout);
app.get('/account', site.account);
app.get('/callback', site.callbackPage);
var auth = oauth2.authenticate({session: false, scope: 'demo'});
app.use(['/protected', '/api', '/me', '/_internal'], auth);
app.get('/me', function(req, res) {
// req.authInfo is set using the `info` argument supplied by
// `BearerStrategy`. It is typically used to indicate scope of the token,
// and used in access control checks. For illustrative purposes, this
// example simply returns the scope in the response.
res.json({ 'user_id': req.user.id, name: req.user.username,
accessToken: req.authInfo.accessToken });
});
signupTestUserAndApp();
//var rateLimiting = require('./middleware/rate-limiting');
//app.middleware('routes:after', rateLimiting({limit: 100, interval: 60000}));
//var proxy = require('./middleware/proxy');
//var proxyOptions = require('./middleware/proxy/config.json');
//app.middleware('routes:after', proxy(proxyOptions));
app.middleware('files',
loopback.static(path.join(__dirname, '../client/public')));
app.middleware('files', '/admin',
loopback.static(path.join(__dirname, '../client/admin')));
// Requests that get this far won't be handled
// by any middleware. Convert them into a 404 error
// that will be handled later down the chain.
app.middleware('final', loopback.urlNotFound());
// The ultimate error handler.
app.middleware('final', loopback.errorHandler());
app.start = function(httpOnly) {
if(httpOnly === undefined) {
httpOnly = process.env.HTTP;
}
server = https.createServer(options, app);
server.listen(app.get('port'), function() {
var baseUrl = (httpOnly? 'http://' : 'https://') + app.get('host') + ':' + app.get('port');
app.emit('started', baseUrl);
console.log('LoopBack server listening # %s%s', baseUrl, '/');
});
return server;};
// start the server if `$ node server.js`
if (require.main === module) {
app.start();
}
function signupTestUserAndApp() {
// Create a dummy user and client app
app.models.User.create({username: 'bob',
password: 'secret',
email: 'foo#bar.com'}, function(err, user) {
if (!err) {
console.log('User registered: username=%s password=%s',
user.username, 'secret');
}
// Hack to set the app id to a fixed value so that we don't have to change
// the client settings
app.models.Application.beforeSave = function(next) {
this.id = 123;
this.restApiKey = 'secret';
next();
};
app.models.Application.register(
user.username,
'demo-app',
{
publicKey: sslConfig.certificate
},
function(err, demo) {
if (err) {
console.error(err);
} else {
console.log('Client application registered: id=%s key=%s',
demo.id, demo.restApiKey);
}
}
);
});
}
I don't get any errors when the server starts up. Thoughts?
Got it figured. More information here https://github.com/strongloop/loopback-gateway/issues/17, but basically I had my rest-api middleware not configured right.
I created a Middleware to get rid of my page request but it seems to run twice...
The first time it run has no error and second time has errors...
This is my code:
app.js file
app.get('/:slug', buildingController.findBuilding, buildingController.getBuilding);
buildings.js file
/**
* Create a Middleware to Find Buildings
*/
exports.findBuilding = function(req, res, next) {
if (!req.isAuthenticated()) {
return res.redirect('/login');
}
Building.find(
{ "uniqueLink": req.params.slug,
"$or": [
{ "_creator": req.user.id }
]
}, function(err, building) {
if (err) {
return next(err);
} else {
if (building.length == 0 || building == null) {
req.flash('errors', { msg: 'You are not allowed to see this building' });
res.redirect('/buildings');
next();
} else {
req.building = building[0];
next();
}
}
}
);
};
/**
* GET /:slug
* Building home page.
*/
exports.getBuilding = function(req, res) {
var building = req.building;
res.render('building/home', {
title: building.name,
building: building
});
};
This is the console output:
Express server listening on port 3000 in development mode
GET /my-slug 200 359.399 ms - -
Good, no errors but then:
TypeError: Cannot read property 'name' of undefined
[...etc...]
Where I'm failing?
On my page everything works fine but I wish to no have errors...
I'm still learning Node.js.
Thanks.
if (building.length == 0 || building == null) {
I think next() shouldn't be called in this case