Setting admin role using connect-roles & Passport.JS - javascript

I am currently trying to set up an admin role in order to access a simple admin page using the following documentation provided via : connect-roles
I ave been banging my head against it for a while and am still lost on how to set a role E.G As of right now am pulling a admin value out of the DB and storing it in a global var for the time being but I have no idea how to use that with connect-roles say to only allow access to my admin page for a specific user.
Can anyone clarify or show an example on how to do this/some guidance as I documentation didn't help me to ensure access to a web page only if the user is an admin?
Ave posted some of the code kinda showing what it looks like at the moment.
Code
var admin = 'Admin';
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',
database : 'test'
});
var passport = require('passport');
var ConnectRoles = require('connect-roles');
var roles = new ConnectRoles();
var passportLocal = require('passport-local');
app.use(passport.initialize());
app.use(passport.session());
app.use(roles.middleware());
passport.use(new passportLocal.Strategy(function (username, password, done) {
connection.query({
sql : 'SELECT * from `userman_users` WHERE `username`= ?AND`password` = sha1(?)',
timeout : 40000, // 40s
values : [username, password]
}, function (error, results, rows) {
if (results.length > 0) {
response = "Success";
} else {
console.log('Error while performing Query.');
response = "Failed";
}
if (response === "Success") {
done(null, {
id : username
});
} else if (response === "Failed") {
done(null, null);
}
});
})
);
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
done(null, {
id : id
});
});
roles.use(function (req, action) {
if (!req.isAuthenticated()) return action === 'access home page';
})
roles.use(function (req) {
if (req.user.role === 'admin') {
return true;
}
});
app.get('/', redirectToIndexIfLoggedIn, function (req, res) {
res.render('login');
});
app.get('/index', checkLoggedIn, function (req, res) {
res.render('index', {
isAuthenticated : req.isAuthenticated(),
user : req.user
});
});
app.get('/admin', user.can('access admin page'), function (req, res) {
res.render('admin');
});
function checkLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}

this is an example:
var express = require('express');
...
var passport = require('passport');
var LocalStrategy = require('passport-local');
var ConnectRoles = require('connect-roles');
...
var app = express();
//===============PASSPORT=================
// Passport session setup.
passport.serializeUser(function(user, done) {
console.log("serializing " + user.username);
done(null, user);
});
passport.deserializeUser(function(obj, done) {
console.log("deserializing " + obj);
// simulate an admin user
obj.role = obj.username == 'admin' ? 'admin' : 'user';
done(null, obj);
});
...
//===============CONNECTION RULES=================
var user = new ConnectRoles({
failureHandler: function (req, res, action) {
// optional function to customise code that runs when
// user fails authorisation
var accept = req.headers.accept || '';
res.status(403);
if (~accept.indexOf('html')) {
res.render('access-denied', {action: action});
} else {
res.send('Access Denied - You don\'t have permission to: ' + action);
}
}
});
...
app.use(passport.initialize());
app.use(passport.session());
app.use(user.middleware());
//anonymous users can only access the home page
//returning false stops any more rules from being
//considered
user.use(function (req, action) {
if (!req.isAuthenticated()) return action === 'access home page';
});
//users logged can access to public pages
user.use(function(req, action){
if(req.isAuthenticated() && action != 'access private page' && action != 'access admin page')
return true;
});
//moderator users can access private page, but
//they might not be the only ones so we don't return
//false if the user isn't a moderator
user.use('access private page', function (req) {
console.log('access private page');
if (req.user.role === 'moderator') {
return true;
}
});
//admin users can access all pages
user.use(function (req) {
if (req.user.role === 'admin') {
return true;
}
});
...
/* GET home page. */
app.get('/', user.can('access home page'), function(req, res, next) {
res.render('index', { title: 'Express' });
});
//displays our signup page
app.get('/signin', function(req, res){
res.render('signin');
});
//sends the request through our local signup strategy, and if successful takes user to homepage, otherwise returns then to signin page
app.post('/local-reg', passport.authenticate('local-signup', {
successRedirect: '/',
failureRedirect: '/signin'
})
);
//sends the request through our local login/signin strategy, and if successful takes user to homepage, otherwise returns then to signin page
app.post('/login', passport.authenticate('local-signin', {
successRedirect: '/',
failureRedirect: '/signin'
})
);
// Simple route middleware to ensure user is authenticated.
app.use(function(req, res, next) {
if (req.isAuthenticated()) { return next(); }
req.session.error = 'Please sign in!';
res.redirect('/signin');
});
//logs user out of site, deleting them from the session, and returns to homepage
app.get('/logout', function(req, res){
var name = req.user.username;
console.log("LOGGIN OUT " + req.user.username)
req.logout();
res.redirect('/');
req.session.notice = "You have successfully been logged out " + name + "!";
});
app.get('/private', user.can('access private page'), function (req, res) {
res.render('private');
});
app.get('/admin', user.can('access admin page'), function (req, res) {
res.render('admin');
});
app.use('/users', users);
....
module.exports = app;
With connect-rules you define the rules do you want to use (user.use in this case). If you pass an action as first parameter the strategy is only used if the action passed in the function is equal to it. Then you trigger the rules in the routes with user.can passing the action. In this example I define an extra filter strategy to grant access to users that are logged and request routes that are not marked with admin or moderator privileges e.g
/* GET home page. */
app.get('/', user.can('access home page'), function(req, res, next) {
res.render('index', { title: 'Express' });
});
After the user is logged, we need to have another strategy in case the user isn't admin or moderator.

U can use framework like sailsJS and npm module sails-generate-auth
And after setup, use your own middleware to block routes
//allow admin only localhost:PORT/admin at policies.js
'admin': ['passport', 'sessionAuth', 'isAdmin'],
'*': ['passport', 'sessionAuth'],
//isAdmin policy
module.exports = function(req, res, next) {
// User is allowed, proceed to the next policy,
// or if this is the last policy, the controller
if (req.user.role == 'admin') {
return next();
}
// User is not allowed
return res.forbidden('You are not permitted to perform this action.');
};

Using the following logic I was able to have admin functionality based on value within the DB:
app.get('/admin', function (req, res) {
connection.query({
sql : 'SELECT role from `auth_users` WHERE `username`= ?',
timeout : 40000, // 40s
values : [req.user['id']]
}, function (error, results, rows) {
if (results[0]['role'] === "admin") {
admin = (results[0]['role']);
res.render('admin', {
isAuthenticated : req.isAuthenticated(),
user : req.user
});
} else {
admin = "";
res.redirect('/index');
}
})
});

Related

Node passport - Handle not returning profile/session with Google Strategy

I'm doing OAuth with passports Google strategy, where I check in the strategy if the user is trying to login or register for the first time.
In the case where for example a user that already has an account tries to register again I don't want to send back a session to the user, instead I simply want to redirect the to some page in the client and alert them that they are already registered.
What I'm currently trying to do is to run done(null, false) if the case is that the user is registered and tries to register again. What I would expect is that it would fail, then go to the specified failureRedirect and redirect the user. Instead it returns these error messages:
InternalOAuthError: Failed to fetch user profile and Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
How do you solve this and handle not returning a session to the user in the callback?
google.router.js
const googleRouter = require("express").Router();
var passport = require("passport");
const CLIENT_URL = "http://localhost:3000/";
// login endpoint
googleRouter.get(
"/google",
passport.authenticate("google", {
scope: ["profile", "email"],
successRedirect: '/auth/login/success',
failureRedirect: '/auth/failure',
state: "login",
})
);
// register endpoint
googleRouter.get(
"/register/google",
passport.authenticate("google", {
scope: ["profile", "email"],
successRedirect: '/auth/login/success',
failureRedirect: '/auth/failure',
state: "register",
})
);
// login/register callback endpoint
googleRouter.get(
"/google/callback",
passport.authenticate("google", {
successRedirect: '/login/success',
failureRedirect: "/auth/failure",
session: true,
}),
(req, res) => {
res.redirect(CLIENT_URL);
}
);
module.exports = googleRouter;
auth.router.js
const authRouter = require("express").Router();
const CLIENT_URL = "http://localhost:3000/";
authRouter.get("/auth/failure", (req, res) => {
res.status(401).json({
success: false,
message: "failure",
}).redirect(CLIENT_URL);
});
module.exports = authRouter;
passport.js
const handleAuthenticationMethod = async (method, userData, provider) => {
if (method === "login") {
const userExists = await validateEmail(userData.emails[0].value);
//check if user is valid
if (userExists) {
return true // return user session
} else {
return false;
}
}
else if (method === "register") {
const userExists = await validateEmail(userData.emails[0].value);
if (!userExists){
//add user to database
const formattedUser = formatUserData(userData, provider);
const user = new User(formattedUser);
await user.save();
return true; //return user session
}
//if user already exists in database
return false;
}
}
passport.use(
new GoogleStrategy(
{
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
passReqToCallback: true,
},
async function (req, accessToken, refreshToken, profile, done) {
const validAuth = await handleAuthenticationMethod(req.query.state, profile, "google")
if (validAuth){
done(null, profile);
}
else{
done(null, false);
}
}
)
);

How to implement User roles in nodejs passportjs

How to implement role based authorization / access control in nodejs using expressjs and passport also how to design Role Middleware perfectly ?
I have two types of login Admin and User
which is best, creating two model and router in the name of admin and user?
1.Checking user isAdmin or not
2.
// To authtenticate the User by JWT Startegy
module.exports = (userType, passport) => {
let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('jwt');
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
if (userType == 'admin') {
Admin.getAdminById(jwt_payload.data._id, (err, user) => {
if (err) return done(err, false);
if (user) return done(null, user);
return done(null, false);
});
}
if (userType == 'users') {
User.getUserById(jwt_payload.data._id, (err, user) => {
if (err) return done(err, false);
if (user) return done(null, user);
return done(null, false);
});
}
}));
}
Why do you want to have 2 places to get user data?
Have users and assign roles to them.
The easiest access control system is: guest, logged in, admin.
So in table users add a role column with values: user, admin.
And now you write middlewares:
const isLogged = function (req, res, next) {
   if (req.user)
     return next ();
   res.send ('unauth')
}
const isAdmin = function (req, res, next) {
   if (req.user.role == 'admin')
     return next ();
   res.send ('only admin')
}
And usage:
app.get('/', (req, res)=>{})
app.get('/profile',isLogged, (req, res)=>{})
app.get('/admin',isLogged, isAdmin, (req, res)=>{})
For more advanced needs try find some ACL modules

Authenticating routes using passport.js in MEAN Stack environment

I was not able to secure individual routes of my adminpanel using passport.js
User Signup is working. Even when I login into panel its successfully redirectly . But the req.isAuthenticate is always returning false value. Hence, I am not able to access routes inside admin panel
Codes
controller/admin.js
var express = require('express'),
router = express.Router(),
session=require('express-session');
module.exports = function (app) {
app.use('/', router);
};
var passport = require('passport');
var flash = require('connect-flash'),
session = require('express-session');
router.use(session({ secret: 'ilovescotchscotchyscotchscotch' ,saveUninitialized: true, resave: true})); // session secret
router.use(passport.initialize());
router.use(passport.session()); // persistent login sessions
router.use(flash());
router.get('/expoadmin/', function(req, res) {
// render the page and pass in any flash data if it exists
res.render('expoadmin/login', { message: req.flash('loginMessage')});
});
// process the login form
router.post('/expoadmin/login', passport.authenticate('admin-login', {
successRedirect : '/expoadmin/dashboard', // redirect to the secure profile section
failureRedirect : '/expoadmin/', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
router.get('/expoadmin/logout', function(req, res){
console.log('logging out');
req.logout();
res.redirect('/expoadmin');
});
router.get('/expoadmin/addadmin', function(req, res) {
// render the page and pass in any flash data if it exists
res.render('expoadmin/signup', { message: req.flash('signupMessage') });
});
// process the signup form
router.post('/expoadmin/signup', passport.authenticate('admin-signup', {
successRedirect : '/expoadmin/admins', // redirect to the secure profile section
failureRedirect : '/expoadmin/addadmin', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
var fetch =require('../adminroutes/eventsfetch.js');
router.get('/expoadmin/dashboard', isLoggedIn,
function (req, res, next) { res.render('expoadmin/index',{ layout : 'dashboard'}); });
router.get('/expoadmin/eventsfetch', isLoggedIn, fetch.view );
// route middleware to make sure
function isLoggedIn(req, res, next) {
var ses=req.session;
console.log(req.user);
console.log(session.user);
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/expoadmin');
}
passport.js
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
var bcrypt = require('bcrypt-nodejs');
// load up the user model
var Admin = require('../app/models/admin');
// expose this function to our app using module.exports
module.exports = function(passport) {
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user._id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =========================================================================
// Admin LOGIN =============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('admin-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
Admin.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error before anything else
console.log(user);
if (err)
return done(err);
// if no user is found, return the message
if (!user)
return done(null, false, req.flash('loginMessage', 'No admin found.')); // req.flash is the way to set flashdata using connect-flash
// if the user is found but the password is wrong
console.log(bcrypt.compareSync(password, user.local.password));
if (!bcrypt.compareSync(password, user.local.password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
console.log(user);
// all is well, return successful user
return done(null, user);
});
}));
};
router.post('/expoadmin/login',function(req,res,next){
passport.authenticate('admin-login', function (err, user, info) {
if (err) {
//send error message here
}
// Generate a JSON response reflecting authentication status
if (!user) {
//send if user not found
}
else{
req.logIn(user, function (err,data) {
if (err) {
//some error with serialization
}
//do your stuff with info here
res.redirect('/expoadmin/dashboard')
});
});
}
})(req, res, next);
})
you callback will be received here in (err,user,info)
send final req as
return done(null,false,user)
now check req.isAuthenticated

Redirect user to previous page after authentication

I'm using Google auth through Passport in my app and I'm attempting to redirect the user back to the original page they requested after successful sign-in. I think that location.reload() may be the problem, but not sure how to solve it.
routes.js:
router.post('/auth/google/return', passport.authenticate('google'), function(req, res) {
res.redirect(req.session.returnTo);
req.session.returnTo = null;
});
middleware.js:
var isAuth = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
req.session.returnTo = req.url;
return res.redirect('/');
}
};
called on button click:
$.post('/auth/google/return', {code: authResult.code, access_token: authResult.access_token}).done(function(data) {
location.reload();
});
Try:
router.post('/auth/google/return', passport.authenticate('google'), function(req, res) {
var backURL = req.header('Referer') || '/';
res.json({redir: backURL});
});
And:
$.post('/auth/google/return', {code: authResult.code, access_token: authResult.access_token}).done(function(data) {
window.location.href = data.redir;
});

How do I use the node.js module passport-google

I am trying to make a node.js web application that tells the user to sign in using their gmail.
So I tried to use the instructions over here: http://passportjs.org/guide/google/. I changed the url www.example.com to localhost, then ran the application. It tells me that it can't find User. Here is the whole log: User.findOrCreate({openID: identifier }, function(err, user) {(and then on the next line) ReferenceError: User is not defined.
You need to define "User" by calling it from a model. Create a User model (if you haven't already) and import it as a variable. E.g.
var User = require('/path/to/User');
Sometimes I find it helpful for debugging to log the callback to the console, to see if the desired output is being spit out.
I just implemented one maybe this will help , I'm using Express the routes section is on the bottom.. Remember to set your host in the Google Key, my App has de full url of the AWS Server
var passport = require('passport');
// ====== Passport and OAuth2 API
var GoogleStretegy = require('passport-google-oauth').OAuth2Strategy;
passport.serializeUser(function (user, done) {
done(null, user);});
passport.deserializeUser(function (obj, done){
done(null, obj);});
// Set Passport Initialize and Sessions
app.use(passport.initialize());
app.use(passport.session());
passport.use(new GoogleStretegy({
clientID: CREDENTIALS.google.GOOGLE_CLIENT_ID,
clientSecret: CREDENTIALS.google.GOOGLE_CLIENT_SECRET,
callbackURL:"<host>/oauth2callback"
},
function (req, accessToken, refreshToken, profile, done) {
process.nextTick(function () {
console.log(JSON.stringify(profile));
console.log(req);
var username= profile.emails[0].value.split('#');
User.findOne({email: profile.emails[0].value,username:username[0]}).exec(function (err,user) {
if(!user){
var user = new User({username: username[0]});
user.set('email',profile.emails[0].value);
user.set('FullName',profile.DisplayName);
user.save(function (err) {
if(err){
console.log(err);
profile=null;
return done(null,profile);
}else {
return done(null, profile);
}
});
}else {
return done(null, profile);
}
});
// return done(null, profile);
});
}
));
/// ROUTES !
router.get('/logout', function (req, res) {
req.session.destroy(function () {
// Google log out
req.logout();
res.redirect('/login');
});
});
//Google OAuth2
router.get('/auth/google',passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/userinfo.profile','https://www.googleapis.com/auth/userinfo.email'] }));
router.get('/oauth2callback', passport.authenticate('google', { failureRedirect: '/login' }), function (req, res) {
res.redirect('/');
});

Categories

Resources