I'm quite new to Node.js and I'm trying to implement an authentication system through an external CAS server. I'm using Passport.js + passport-cas2 but it's always redirecting me to the failureRedirect page even though the CAS correctly authenticated me. Here is my code:
var SocketIOFileUpload = require('socketio-file-upload'),
socketio = require('socket.io'),
express = require('express'),
path = require('path'),
express = require('express'),
passport = require('passport'),
session = require('express-session'),
bodyParser = require('body-parser');
var CasStrategy = require('passport-cas2').Strategy;
var cas = new CasStrategy({
casURL: 'https://my.cas.server'
},
function(username, profile, done) {
console.log("authenticating");
done(null, new User());
});
var app = express()
.use(bodyParser.urlencoded({ extended: true }))
.use(SocketIOFileUpload.router)
.use(passport.initialize());
passport.use(cas);
app.use(session({ secret: 'my secret phrase' }))
.use(passport.session())
.get('/', function(req, res){
res.redirect('/auth/cas');
})
.get('/auth/cas',
passport.authenticate('cas', { failureRedirect: '/error', successRedirect: '/upload' }),
function(req, res) {
// Successful.
res.redirect('/upload');
})
.use('/upload', function(req, res, next){
if (req.user)
return express.static(path.join(__dirname, 'html'));
else
res.redirect('/auth/cas');
})
.get('/error', function(req, res) {
res.send('Error in authentication. Please Try Again.');
})
.listen(8080, function () {
console.log('Upload Server started on http://localhost:8080');
});
The console.log("authenticating") isn't even executed at all!
Thanks for your help.
Okay, I fixed it, my CAS server certificated was self-signed and I had to edit the passport-cas2 source in order for it to accept the certificate.
Related
I have a basic login page in HTML where username and password fields are handled in javascript and the inputs are sent back to my Node API for a full AD authentication.
I have 4 more HTML sites which should only be accesible if the user has authenticated. The authentication part running in Node app works perfectly fine, however, I am not able to handle a session for the users who have logged in.
I also want to make all the 4 HTML sites inaccessible if the login fails or when the user logs out.
How do I handle the accessibility part by simply using HTML and Vanilla JS?
login.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var router = express.Router();
var cors = require('cors');
var ActiveDirectory = require('activedirectory');
const session = require('express-session');
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.use(session({
name: 'session.sid',
secret: 'entersomepasswordhere',
resave: false,
saveUninitialized: false
}));
var port = process.env.PORT || 8080;
app.use('/', router);
router.post('/api/Login1', function(req, res)
{
var username = req.body.username;
var password = req.body.password;
console.log(username);
var config = {
url: 'abc',
baseDN: 'dc=abc,dc=abc'
};
var ad = new ActiveDirectory(config);
// Authenticate
ad.authenticate(username, password, function(err, auth) {
if (err) {
res.send("Login Failed. Incorrect username or password");
console.log('ERROR: '+JSON.stringify(err));
return;
}
if (auth) {
console.log('Authenticated!');
req.session.loggedin = true;
res.redirect('/test.html');
}
else {
console.log('Authentication failed!');
res.send("Login Failed. Incorrect username or password");
}
});
});
router.get('/test.html', function(req, res) {
if (req.session.loggedin == true) //check if user is loggedin, replace with your variables/checks
res.sendFile('/absolutepath/test.html');
else
res.redirect('/Login1');
})
app.use(cors());
app.listen(port);
console.log('Listening at port ' + port);
I think I know what the problem is. The core module just handles every request for you, therefore every http request first looks in the core middleware if it finds a matching html file. You need to place
app.use(cors());
After you've defined your routes and define a custom route to your test.html. See the following example:
var express = require('express');
var app = express();
var router = express.Router();
var cors = require('cors');
var port = process.env.PORT || 8080;
//use routes on the localhost:8080 path
app.use('/', router);
//Relevant part:
router.get('/test.html', function(req, res) {
var loggedin = true; //false if not loggedin
if (loggedin)
res.sendFile(__dirname + '/test.html');
else
res.redirect('https://www.google.com/');
})
//This needs to be after the routes
app.use(cors());
app.listen(port);
console.log('Listening at port ' + port);
You can set loggedin to false to see what happens if a user isn't loggedin and true if a user is loggedin.
UPDATE
In order to save if a user is loggedin, i recommend using the express-session module: https://expressjs.com/en/resources/middleware/cookie-session.html
You can include it like the following:
const session = require('express-session');
app.use(session({
name: 'session.sid',
secret: 'entersomepasswordhere',
resave: false,
saveUninitialized: false
}));
After authenticating you can just set
req.session.loggedin = true;
and then just check if
req.session.loggedin == true
Note: you can replace loggedin with any variable name you like, and you can also set multiple session cookies.
In your case just set req.session.loggedin = true before you redirect to your test.html and then perform the check in there.
I'm trying to set up a "backend" for a webpage I've created. So some pages can only be accessible if the user is logged in. I've built the basic functionality for this and I can do a simple validation in whether the user is logged-in. But the redirecting to the page is where I get stuck.
Example:
var auth = function(req,res,next){
if (req.session.loggedin){
return next();
} else{
return res.sendStatus(401);
}
};
app.get('/list-video', auth, function (req, res) {
res.redirect('/list-video');
});
So my issue is that '/list-video' is the page I want to protect and only be accessible when the user successfully logged in. But after the validation, I'm redirecting to the same page: '/list-video'. this doesn't seem to work as I'm obviously getting stuck in a loop. I have tried redirecting to a different page like '/list-audio' and of course this works fine.
Can someone advise on how this is usually done? Do I need to create a separate link that I can redirect to? (I do want to prevent users going to that link manually by typing the URL in the browser.)
Any help or advice will be greatly appreciated!
My complete app.js code:
const express = require('express');
const fileUpload = require('express-fileupload');
const bodyParser = require('body-parser');
const mysql = require('mysql');
const path = require('path');
const app = express();
const session = require('express-session');
const { getHomePage } = require('./routes/index');
const { getBackendPage } = require('./routes/backend');
const { getVideoPage, listVideoPage, editVideoPage, editVideo, deleteVideo, addVideoPage, addVideo } = require('./routes/video');
const { getEbookPage } = require('./routes/ebook');
const { getMusicPage } = require('./routes/music');
const { getGamePage } = require('./routes/game');
const { getShopPage } = require('./routes/shop');
const port = 5000;
const db = mysql.createConnection({
host: '127.0.0.1',
user: 'user',
password: 'bla',
database: 'test'
db.connect((err) => {
if (err) {
throw err;
}
console.log('Connected to database');
});
global.db = db;
// configure middleware
app.set('port', process.env.port || port); // set express to use this port
app.set('views', __dirname + '/views'); // set express to look in this folder to render our view
app.set('view engine', 'ejs'); // configure template engine
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json()); // parse form data client
app.use(express.static(path.join(__dirname, 'public'))); // configure express to use public folder
app.use(fileUpload()); // configure fileupload
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true
}));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
/ passenger views
app.get('/', getHomePage);
app.get('/backend', getBackendPage);
app.get('/video', getVideoPage);
app.get('/ebook', getEbookPage);
app.get('/music/:id', getMusicPage);
app.get('/game', getGamePage);
app.get('/shop', getShopPage);
// backend views video
app.get('/edit-video/:id', editVideoPage);
app.post('/edit-video/:id', editVideo);
app.get('/add-video', addVideoPage);
app.post('/add-video', addVideo);
app.get('/delete-video/:id', deleteVideo);
// login screen
app.post('/auth', function (request, response) {
var username = request.body.username;
var password = request.body.password;
if (username && password) {
db.query('SELECT * FROM accounts WHERE username = ? AND password = ?', [username, password], function (error, results, fields) {
if (results.length > 0) {
request.session.loggedin = true;
request.session.username = username;
response.redirect('/');
} else {
response.send('Incorrect Username and/or Password!');
}
response.end();
});
} else {
response.send('Please enter Username and Password!');
response.end();
}
});
var auth = function(req,res,next){
if (req.session.loggedin){
return next();
} else{
return res.sendStatus(401);
}
};
app.get('/list-video', auth, function (req, res) {
res.redirect('/list-video');
});
app.listen(port, () => {
console.log(`Server running on port: http://localhost:${port}`);
});
Move your protected pages to a different directory (outside the folder where your public static files are) and serve the express.static after the authentication middleware, something like this:
app.use('/', express.static(path.join(__dirname, 'public'))); //notice I have no auth middleware
app.use('/mysecretpages', auth, express.static(path.join(__dirname, 'secret'))); //notice I DO have auth middleware
change it to:
var auth = function(req,res,next){
if (!req.session.loggedin){
return res.redirect("/login");
} else{
return next();
}
};
app.get('/list-video', auth);
That way you will redirect to the login page if the user isn't authenticated and continue if he is.
I am trying to implement a ReactJS application that runs with a Node.JS with express and I am using PassportJS google oauth20 for the authentication.
The authentication part going without any problems and when I open my chrome dev tools I can see that I have 2 cookies injected after the auth, the problem is that when i try to get them with react-cookie or js-cookie or event with document.cookie nothing comes back
The App for Express is based on the express generator
App:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var passport = require('passport');
const passportSetup = require('./config/passport');
const cookieSession = require('cookie-session');
// some router imports here
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
/
app.use(cookieSession({
maxAge: 60 * 60 * 1000,
keys: ['mysuperseacretcat']
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', indexRouter);
app.use('/auth', authRouter);
app.use('/users', usersRouter);
app.use('/orders', ordersRouter);
app.use('/orderdetails', orderDetailsRouter);
app.use('/suppliers', suppliersRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.get("*", function(req, res) {
res.sendFile(path.join(__dirname, "client/build", "index.html"));
});
module.exports = app;
Passport config :
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20");
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
done(null, id);
});
passport.use(
new GoogleStrategy(
{
callbackURL: "/auth/google/redirect",
clientID: "ENV",
clientSecret: "ENV"
},
(accessToken, refreshToken, profile, done) => {
if (profile._json.email.split('#')[1] !== 'xxx' || profile._json.hd !== 'xxx') {
done(null, false);
} else {
done(null, profile)
}
}
)
);
Google Auth Routes:
router.get(
"/google", passport.authenticate("google", {
scope: ["profile", "email"]
})
);
router.get("/google/redirect", passport.authenticate('google'), (req, res) => {
res.redirect('/');
});
I can't seem to understand how am I supposed to check after the auth process that the user is logged in with react.
Also, I do not use a DB store as I don't need one I just need to make sure a user as logged in. (is that something that can be done or storing the user is a must?)
What am I missing?
I'm trying to add local authentication to my node.js app. After following the tutorial on: https://scotch.io/tutorials/easy-node-authentication-setup-and-local I have run into error: "TypeError: app.use() requires a middleware function".
I think this is related to the app.use(indexRoutes) in my app.js file but I'm not sure how to fix this? Any help would be greatly appreciated.
Here is my code so far:
app.js:
var express = require('express'),
session = require("express-session"),
bodyParser = require('body-parser'),
app = express().use(bodyParser.json()), //creates express http server
passport = require('passport'),
sanitizer = require('express-sanitizer'),
mongoose = require("mongoose"),
cookieParser = require('cookieparser'),
dotnev = require('dotenv').config(),
https = require('https'),
flash = require('connect-flash'),
fs = require('fs'),
config = require('./config/config'),
_ = require("underscore");
require('./config/passport')(passport);
var indexRoutes = require("./routes/index")(app, passport);
app.use(bodyParser.urlencoded({extended: true}));
app.use(sanitizer());
app.use(express.static(__dirname + "/public")); //tells express to serve the contents of the public directory
app.use(cookieParser);
//no longer need to specify that the view files are .ejs
app.set("view engine", "ejs");
app.use(session({
secret: "akjjkjnisaiuu8998323jdkadsih892rhoisdfasl",
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 1200000
}
}));
app.use(passport.initialize);
app.use(passport.session());
app.use(flash());
app.use(indexRoutes);
mongoose.connect(process.env.MONGOLAB_URL, { useNewUrlParser: true });
index.js:
var express = require("express"),
router = express.Router(),
_ = require("underscore"),
User = require("../models/user"),
auth = require("../routes/auth"),
config = require('../config/config'),
freshbooks = require("../modules/freshbooks"),
quickbooks = require("../modules/quickbooks");
module.exports = function(router, passport){
//------------------------------------//
//***------------ROUTES------------***//
//------------------------------------//
router.get("/", function(req, res) {
res.render("landing");
});
router.get("/register", auth.optional, function(req, res) {
res.render("register");
});
router.get("/login", auth.optional, function(req, res) {
res.render("login");
});
router.get("/admin", isLoggedIn, function(req, res) {
res.render('admin', {
user : req.user // get the user out of session and pass to template
});
});
//------------------------------------//
//***-------------AUTH-------------***//
//------------------------------------//
router.post('/register', passport.authenticate('local-signup', {
successRedirect : '/admin', // redirect to the secure profile section
failureRedirect : '/register', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
function isLoggedIn(req, res, next) {
// 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('/');
}
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
}
Thanks in advance for any help!
In app.js
var { registerIndexRoutes } = require("./routes/index");
var indexRoutes = registerIndexRoutes(router, passport);
app.use(indexRoutes);
and index.js
const registerIndexRoutes = function(router, passport){
//------------------------------------//
//***------------ROUTES------------***//
//------------------------------------//
router.get("/", function(req, res) {
res.render("landing");
});
return router;//important;
}
module.exports = { registerIndexRoutes };
It will help you.
You're getting that error because, this function, module.exports = function(router, passport){, is not a valid middleware.
From express docs: Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle.
The syntax goes:
function(req, res, next) {
// Implement the middleware function based on the options object
next()
}
req: HTTP response argument to the middleware function, called "res" by convention.
res: HTTP request argument to the middleware function, called "req" by convention.
next: Callback argument to the middleware function, called "next" by convention.
When you invoked this function, function(router, passport){:
var indexRoutes = require("./routes/index")(app, passport);
indexRoutes, contains the return value of function(router, passport) which does not return a middleware function (It returns undefined).
Two ways you can solve the issue:
Change your import:
// remove this line and put the below instead
app.use(cookieParser);
// and modify and move your import
require("./routes/index")(app, passport);
Use Express router: Change your index.js like
// note your exports it's not a function, you're exporting this **router** object -> router = express.Router(),
module.exports = router;
//------------------------------------//
//***------------ROUTES------------***//
//------------------------------------//
router.get("/", function(req, res) {
res.render("landing");
});
router.get("/register", auth.optional, function(req, res) {
res.render("register");
});
...
And change your import to:
var indexRoutes = require("./routes/index");
So the server is running and listening to port 3000 which isn't being blocked
as far as I can tell, but when I try and load the page it hangs for a while before providing the following message:
"This page isn’t working
localhost didn’t send any data.
ERR_EMPTY_RESPONSE
I'm not sure why I can't get anything to pull through even when I adjust the get('/") homepage to render something simple. There also aren't any errors pulling through the terminal so I'm unsure how to diagnose the problem.
My app.js code:
const express = require('express');
const path = require('path');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const expressValidator = require('express-validator');
const flash = require('connect-flash');
const session = require('express-session');
mongoose.connect('mongodb://localhost/nodekb');
let db = mongoose.connection;
// Check connection
db.once('open', function(){
console.log('Connected to MongoDB');
});
// Check for DB errors
db.on('error', function(err){
console.log(err);
});
// Init App
const app = express();
// Bring in Models
let Article = require('./models/article');
// Load View Engine
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// Body Parser Middleware
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
// Set Public Folder
app.use(express.static(path.join(__dirname, 'public')));
// Express Session Middleware
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: true
}));
// Express Messages Middleware
app.use(require('connect-flash')());
app.use(function (req, res, next) {
res.locals.messages = require('express-messages')(req, res);
next();
});
// Express Validator Middleware
app.use(expressValidator);
// Home Route
app.get('/', function(req, res){
Article.find({}, function(err, articles){
if(err){
console.log(err);
} else {
res.render('index', {
title:'Articles',
articles: articles
});
}
});
});
// Route Files
let articles = require('./routes/articles');
let users = require('./routes/users');
app.use('/articles', articles);
app.use('/users', users);
app.listen(3000, function(){
console.log("We are running on port 3000");
});
I think the problem is your query is fetching empty array.
I have added condition in callback of query to check array length of articles.
app.get('/', function(req, res){
Article.find({}, function(err, articles){
if(err){
console.log(err);
res.json(err);
}else if(articles.length == 0){
console.log("Articles not found");
res.json({error : "Articles not found"});
} else {
console.log("Articles found");
res.render('index', {
title:'Articles',
articles: articles
});
}
});
});
I hope it will help you.