user2440712
user2440712

Reputation: 719

restify.js + passport.js not authenticating GET request

I have the following code, and every time I type in 0.0.0.0:3000/user?apikey=xxx, the code within local strategy never runs and it goes to "unauthorized" page directly. I tried to remove passport.authenticate from server.get('/user'). In the debug mode, I could see that 'apikey' is parsed out to request parameter map. So the problem here is that passport is not able to authenticate get request. Any help will be greatly appreciated. Thanks!

var restify = require('restify');
// Create server
var server = restify.createServer({
    name: 'server'
});
server.use(restify.queryParser());
server.use(restify.bodyParser());


var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
    function (apikey, done) {
        console.log('Entered authentication.');
        done(null, null);
    }
));


//specify route
server.get('/user', passport.authenticate('local'), function (req, res) {
    console.log(req.params);
    res.end('haha');
});

server.listen(3000, function () {
    console.log('%s listening at %s', server.name, server.url)
});

Upvotes: 2

Views: 3445

Answers (2)

occasl
occasl

Reputation: 5454

An alternative approach is to simply use HTTP BASIC authentication. This way the userid/password is sent in the authorization header rather than part of the URI as this is a fairly common approach for securing services (just be sure you do this over HTTPS). I wrote this smallish module to do exactly that borrowed in part from some of the examples for passport-http.

var restify = require('restify'),
    userId = process.env.serviceID,
    pwd = process.env.servicePassword,
    passport = require('passport'),
    BasicStrategy = require('passport-http').BasicStrategy;

passport.use(new BasicStrategy(
    function (username, password, done) {
        findByUsername(username, function (err, user) {
            if (err) {
                return done(err);
            }
            if (!user) {
                return done(null, false, { message: 'Incorrect username.' });
            }
            if (user.password !== password) {
                return done(null, false, { message: 'Incorrect password.' });
            }
            return done(null, user);
        });
    }
));

var users = [
    { id: 1, username: userId, password: pwd}
];

function findByUsername(username, fn) {
    for (var i = 0, len = users.length; i < len; i++) {
        var user = users[i];
        if (user.username === username) {
            return fn(null, user);
        }
    }
    return fn(null, null);
}

exports.authenticate = function (req, res, next, callback) {
    passport.authenticate('basic', function (err, user) {
        if (err) {
            console.log(err);
            return next(err);
        }
        if (!user) {
            var error = new restify.InvalidCredentialsError("Failed to authenticate to ma-services.");
            console.log(error);
            res.send(error);
            return next();
        }

        callback(req, res, next);
    })(req, res, next);
};

To call it, I simply do the following from exported API calls that the server will call:

var basicAuth = require(__dirname + '/../utils/authn.js');
exports.count = function (req, res, next) {
    basicAuth.authenticate(req, res, next, function() {
        validateParam(req.params.uid, next);
        var url = '/count/' + encodeURIComponent(req.params.uid);

        processRequest(req, res, next, url);
    });
};

Upvotes: 0

user568109
user568109

Reputation: 47993

The LocalStrategy is used for authenticating users via username and password. The passed function requires 3 arguments: username, password and a callback done. Your function only takes two apikey and done.

This strategy is not suitable for you as it authenticates the user via the credentials posted in the request, i.e. from a login page, which is helpful if you are using sessions. You on the other hand have to authenticate every GET request via apikey string in the url. So instead you should write a middleware for authenticating that.

server.use(function(req,res,next){
  key=req.query['apikey']; //get key from url
  //authenticate it
  if(valid(key))
  next();
  else
  res.redirect('/unauthorized');
});

Use this before your router.

Upvotes: 4

Related Questions