We are trying to use passportjs for authenticating using ADFS. However, an error is thrown despite adding cors to our requests. Added both the server code and client code. The server code is also available here.
auth0/node-jsonwebtoken#59
Server - Code
'use strict';
// N.B. Encoding problems are being caused by jsonwebtoken
// auth0/node-jsonwebtoken#59
var app = require('express')(),
cookieParser = require('cookie-parser'),
jwt = require('jsonwebtoken'),
passport = require('passport'),
OAuth2Strategy = require('passport-oauth').OAuth2Strategy,
fs = require('fs');
var cors = require('cors');
var https = require('https');
console.warn('Not verifying HTTPS certificates');
https.globalAgent.options.rejectUnauthorized = false;
// Exported from ADFS
var adfsSigningPublicKey = fs.readFileSync('ADFS-Signing.cer','utf8');
var cert = convertCertificate(adfsSigningPublicKey);
function validateAccessToken(accessToken) {
var payload = null;
try {
payload = jwt.verify(accessToken, cert,{algorithms: ["HS256"], ignoreExpiration: true});
}
catch(e) {
console.warn('Dropping unverified accessToken', e);
}
return payload;
}
function convertCertificate (cert) {
//Certificate must be in this specific format or else the function won't accept it
var beginCert = "-----BEGIN CERTIFICATE-----";
var endCert = "-----END CERTIFICATE-----";
cert = cert.replace("\n", "");
cert = cert.replace(beginCert, "");
cert = cert.replace(endCert, "");
var result = beginCert;
while (cert.length > 0) {
if (cert.length > 64) {
result += "\n" + cert.substring(0, 64);
cert = cert.substring(64, cert.length);
}
else {
result += "\n" + cert;
cert = "";
}
}
if (result[result.length ] != "\n")
result += "\n";
result += endCert + "\n";
return result;
}
// Configure passport to integrate with ADFS
var strategy = new OAuth2Strategy({
authorizationURL: 'https://sso.xxx.com/adfs/oauth2/authorize',
tokenURL: 'https://sso.xxx.com/adfs/oauth2/token',
clientID: 'xxxxxxxx-xxxx-xxxx-xxxx-0cxxx4489fa', // This is just a UID I generated and registered
clientSecret: 'shhh-its-a-secret', // This is ignored but required by the OAuth2Strategy
callbackURL: 'http://localhost:3000/getAToken'
},
function(accessToken, refreshToken, profile, done) {
if (refreshToken) {
console.log('Received but ignoring refreshToken (truncated)', refreshToken.substr(0, 25));
} else {
console.log('No refreshToken received');
}
console.log("done ** " + profile);
done(null, profile);
});
strategy.authorizationParams = function(options) {
return {
resource: 'iggggggg' // An identifier corresponding to the RPT
};
};
strategy.userProfile = function(accessToken, done) {
done(null, accessToken);
};
passport.use('provider', strategy);
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
// Configure express app
app.use(cookieParser());
app.use(cors());
app.use(passport.initialize());
// app.options('*', cors());
app.use(function(req, res, next) {
// res.header('Content-type', 'text/plain')
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
res.header('Access-Control-Allow-Methods', 'GET,POST');
//res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if ('OPTIONS' == req.method) {
res.send(200);
} else {
next();
}
});
app.get('/login', passport.authenticate('provider'),function(req, res) {
// Beware XSRF...
// res.json({ message: "ok", token: req.user });
});
app.get('/getAToken', passport.authenticate('provider'), function(req, res) {
// Beware XSRF...
console.log("*********************************");
res.cookie('accessToken', req.user);
res.redirect('/');
//res.json({ message: "ok", token: req.user });
});
app.get('/', function (req, res) {
console.log('default is called');
req.user = validateAccessToken(req.cookies['accessToken']);
res.send(
!req.user ? 'Log In' : 'Log Out' +
'
' + JSON.stringify(req.user, null, 2) + '
');
});
// app.get('/logout',cors(), function (req, res) {
// res.clearCookie('accessToken');
// res.redirect('/');
// });
app.listen(3000);
console.log('Express server started on port 3000');
And my client code is below.
const params = {
method: 'GET',
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST",
"Access-Control-Allow-Headers": "Content-type",
"Access-Control-Allow-Credentials": true,
},
withCredentials: true
}
axios('/login', params)
.then(response => {
response.data;
})
.catch(error => {
debugger;
console.log('error');
})`
The error received is below.
Response to preflight request is invalid. Is something wrong with my cors?
Related
I am learning mean stack by making a social media web app like twitter
But at the time of signup or login i am getting success and a user also was created in database but the page does not redirects and gives error 500
The following is the code
App.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
require('./models/models.js');
var index = require('./routes/index');
var api = require('./routes/api');
var authenticate = require('./routes/authenticate')(passport);
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/chirp-test');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: true
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
var initPassport = require('./passport-init');
initPassport(passport);
app.use('/', index);
app.use('/auth', authenticate);
app.use('/api', api);
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
authenticate.js
var express = require('express');
var router = express.Router();
module.exports = function(passport){
router.get('/success', function(req, res){
res.send({state: 'success', user: req.user ? req.user : null});
});
router.get('/failure', function(req, res){
res.send({state: 'failure', user: null, message: "Invalid username or password"});
});
//log in
router.post('/login', passport.authenticate('login', {
successRedirect: '/auth/success/',
failureRedirect: '/auth/failure'
}));
//sign up
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/auth/success',
failureRedirect: '/auth/failure'
}));
//log out
router.get('/signout', function(req, res) {
req.logout();
res.redirect('/');
});
return router;
}
passport-init.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var bCrypt = require('bcrypt-nodejs');
var mongoose = require('mongoose');
var User = mongoose.model('User');
var Post = mongoose.model('Post');
module.exports = function(passport){
passport.serializeUser(function(user, done) {
return done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user){
if(err){
return done(err, false);
}
if(!user){
return done('User not found', false);
}
return done(user, true);
})
});
passport.use('login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
User.findOne({'username': username}, function(err, user){
if(err){
return done(err, false);
}
if(!user){
return done('Username does not exist ', false);
}
if(!isValidPassword(user, password)){
return done('Incorrect password', false);
}
return done(null, user);
});
}
));
passport.use('signup', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
User.findOne({'username' : username}, function(err, user){
if(err){
return done(err, false);
}
if(user){
return done('Username already taken', false);
}
var newUser = new User();
newUser.username = username;
newUser.password = createHash(password)
newUser.save(function(err, user){
if(err){
return done(err, false);
}
console.log('Successfully signed up User ' + username);
return done(null, newUser);
});
});
})
);
var isValidPassword = function(user, password){
return bCrypt.compareSync(password, user.password);
};
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
};
};
The error is somewhere in your passport-init.js where you invoke done() with a string as a first argument, e.g. done('User not found', false)
What you want to do instead is throw an actual error:
done(new Error('User not found'), false);
and then handle it later. Once you find the error you can find the reason for redirect to (not) work.
I am trying to select items from sql server but I am getting below error. My SELECT statement right after completion on INSERT statement. What should I do to select properly without this error? Should I create separation connection?
Promise { }
node.js
//Receive from Angular Server
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const http = require('http');
var sql = require('mssql');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.all("/*", function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
next();
});
app.listen(1433, function (err) {
if (err)
console.log(err);
else
console.log('Example app listening on port 1433!')
})
var config = {
};
app.post('/ping', function (req, res) {
res.send(res.body);
var jsondata = JSON.stringify(req.body);
var data = JSON.parse(jsondata);
sql.connect(config, function (err) {
if (err)
console.log(err);
else
console.log("Connection successful");
var request = new sql.Request();
request.input
.input('Loc', data.Location).input('ara', data.area)
.query('INSERT INTO Local_RMS (Location, Shift, PlanWld, ActualWld, OrWld, PlanPnt, ActualPnt, OrPnt, PlanAssy, OrAssy) VALUES (#Loc, #ara', (err, result) => {
if (err)
console.log(err);
else
console.log("Rows Affected : " + request.rowsAffected);
})
const result = request.query `SELECT * FROM Local_RMS WHERE DateCreated BETWEEN '11-24-2017 11:17:00' and '11-24-2017 11:18:59'`;
console.log(result); //error "Promise { <pending> }"
})
});
I would like to add to add a refresh token to a header in middleware as seen in the first answer of this question: implementing refresh-tokens with angular and express-jwt
Backend - middleware:
jwt.verify(token, config.secret, function(err, decoded) {
if (err) {
res.status(401);
return res.json({ success: false, message: 'Authentication failed' });
} else {
var token_exp = new Date(decoded.exp * 1000);
var date = new Date();
var difference = (token_exp.getTime() - date.getTime()) / 60000;
if(difference < (config.expireTimeToken / 2 )){
var expires = config.expireTimeToken + 'm';
var token = jwt.refreshToken(decoded);
res.setHeader('Authorization', 'Bearer ' + token);
next();
}else{
req.decoded = decoded;
next();
}
}
});
Front-end interceptor:
module.exports = function ($injector) {
return {
request: function (config) {
var CoreService = $injector.get('CoreService');
config.headers['x-access-token'] = CoreService.getToken();
return config;
},
response: function(response) {
var receivedToken = response.headers('authorization');
console.log(receivedToken);
return response;
}
};
};
However, whenever i set a header it is not received by the interceptor on the client side. When i debug the res.header in my npm console, the set header 'Authorization' is in '_headers' instead of 'headers'.
How can i solve this.
In an express middleware, you can set the header using res.set(field, [value]) or res.header(field, [value]) (alias for the same function). setHeader is not the express method, but the native node.js, I assume this might be causing the problem.
I am trying to send an email using a contact form in AngularJS, the server side is programmed in NodeJS, to send the email by smtp I am using the nodemailer library, the AngularJS side the form is sending the data, but the server side not received this data, only show me an object named IncomingMessage with many items, but I don't see my email data.
Angular side
angular.module('contactApp', [])
.factory('postEmailForm',['$http',function($http){
return {
postEmail: function(emailData,callback){
console.log(emailData);
$http.post("/contact-form", emailData).success(callback);
}
}
}])
.controller('ContactController', function ($scope,postEmailForm) {
$scope.sendMail = function () {
console.log("Entro!");
var req = {
headers: {
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content- Type, Accept'
},
data:
{
contactName : this.contactName,
contactEmail : this.contactEmail,
contactMsg : this.contactMsg
}
}
postEmailForm.postEmail(req, function (res) {
console.log(req);
if (res.type == false) {
//do something
}else{
console.log("OK");
}
})
};
});
Server side
var express=require('express');
var nodemailer = require("nodemailer");
var app = express();
var serveStatic = require('serve-static');
var http = require('http');
app.use(serveStatic("."));
app.get('/',function(req,res){
res.sendfile('index.html');
});
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "sending email",
pass: "sending pass"
}
});
app.post('/contact-form',function(req,res){
//Your NodeMailer logic comes here
console.log(req.data);
var mailOptions={
from : req.data.contactEmail,
to: recipient email
subject : "Contact",
text : req.data.contactMsg
}
console.log(mailOptions);
smtpTransport.sendMail(mailOptions, function(error, response){
if(error){
console.log('Server error ' + error);
res.end("error");
}else{
console.log("Message sent: " + response.message);
res.end("sent");
}
});
I forgot add body-parser on the server side, to parse the data
var bodyParser = require('body-parser');
app.use(bodyParser.json());
I am new to PassportJS and AngularJS and I have a doubt about how to proceed with this authorization.
I have Spring REST API Secured by Oauth2, but I have to send together user credentials like this:
[http://localhost:8080/myapp/oauth/token]
grant_type=password&username=email&password=password&client_id=09e749d8309f4044&client_secret=189309492722aa5a&scope=read
In client my application I use passport and I want to authorize/authenticate my users, how can I create a Stratagy for this ?
I will send here my server config and my security Lib.
Server.js
var fs = require('fs');
var http = require('http');
var https = require('https');
var privateKey = fs.readFileSync(__dirname + '/cert/privatekey.pem').toString();
var certificate = fs.readFileSync(__dirname + '/cert/certificate.pem').toString();
var credentials = {key: privateKey, cert: certificate};
var express = require('express');
var config = require('./config.js');
var passport = require('passport');
var security = require('./lib/security');
var xsrf = require('./lib/xsrf');
var protectJSON = require('./lib/protectJSON');
require('express-namespace');
var app = express();
var secureServer = https.createServer(credentials, app);
var server = http.createServer(app);
// Serve up the favicon
app.use(express.favicon(config.server.distFolder + '/favicon.ico'));
// First looks for a static file: index.html, css, images, etc.
app.use(config.server.staticUrl, express.compress());
app.use(config.server.staticUrl, express['static'](config.server.distFolder));
app.use(config.server.staticUrl, function(req, res, next) {
res.send(404); // If we get here then the request for a static file is invalid
});
app.use(protectJSON);
app.use(express.logger()); // Log requests to the console
app.use(express.bodyParser()); // Extract the data from the body of the request - this is needed by the LocalStrategy authenticate method
app.use(express.cookieParser(config.server.cookieSecret)); // Hash cookies with this secret
app.use(express.cookieSession()); // Store the session in the (secret) cookie
app.use(passport.initialize()); // Initialize PassportJS
app.use(passport.session()); // Use Passport's session authentication strategy - this stores the logged in user in the session and will now run on any request
app.use(xsrf); // Add XSRF checks to the request
security.initialize(config.oauth.authorize_url, config.oauth.access_token, config.oauth.apiKey, config.oauth.secretKey, config.oauth.scopereq); // Add a Oauth strategy for handling the authentication
app.use(function(req, res, next) {
if ( req.user ) {
console.log('Current User:', req.user.firstName, req.user.lastName);
} else {
console.log('Unauthenticated');
}
next();
});
app.post('/login', security.login);
app.post('/logout', security.logout);
// Retrieve the current user
app.get('/current-user', security.sendCurrentUser);
// Retrieve the current user only if they are authenticated
app.get('/authenticated-user', function(req, res) {
security.authenticationRequired(req, res, function() { security.sendCurrentUser(req, res); });
});
// Retrieve the current user only if they are admin
app.get('/admin-user', function(req, res) {
security.adminRequired(req, res, function() { security.sendCurrentUser(req, res); });
});
// This route deals enables HTML5Mode by forwarding missing files to the index.html
app.all('/*', function(req, res) {
// Just send the index.html for other files to support HTML5Mode
res.sendfile('index.html', { root: config.server.distFolder });
});
// A standard error handler - it picks up any left over errors and returns a nicely formatted server 500 error
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
// Start up the server on the port specified in the config
server.listen(config.server.listenPort, 'localhost', 511, function() {
// // Once the server is listening we automatically open up a browser
var open = require('open');
open('http://localhost:' + config.server.listenPort + '/');
});
console.log('Deengo Business App Server - listening on port: ' + config.server.listenPort);
secureServer.listen(config.server.securePort);
console.log('Deengo Business App Server - listening on secure port: ' + config.server.securePort);
lib/security.js
var express = require('express');
var passport = require('passport');
var app = express();
var BearerStrategy = require('passport-http-bearer').Strategy
var filterUser = function(user) {
if ( user ) {
return {
user : {
id: user._id.$oid,
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
admin: user.admin
}
};
} else {
return { user: null };
}
};
var security = {
initialize: function(_authorize_url, _access_token, _apiKey, _secretKey, _scopereq) {
passport.use('deengo-auth', new OAuth2Strategy({
authorizationURL: _authorize_url,
tokenURL: _access_token,
clientID: _apiKey,
clientSecret: _secretKey,
callbackURL: 'http://localhost:3000/oauth/autorize/callback',
scope: _scopereq,
passReqToCallback: true,
skipUserProfile: true
},
function(req, accessToken, refreshToken, profile, done) {
client['headers']['authorization'] = 'bearer ' + req.session.passport.accessToken;
User.findOrCreate({ clientId: clientId }, function(err, user) {
done(err, user);
});
}
));
},
authenticationRequired: function(req, res, next) {
console.log('authRequired');
if (req.isAuthenticated()) {
next();
} else {
res.json(401, filterUser(req.user));
}
},
adminRequired: function(req, res, next) {
console.log('adminRequired');
if (req.user && req.user.admin ) {
next();
} else {
res.json(401, filterUser(req.user));
}
},
sendCurrentUser: function(req, res, next) {
res.json(200, filterUser(req.user));
res.end();
},
login: function(req, res, next) {
console.log(req.body.email);
console.log(req.body.password);
function authenticationFailed(err, user, info){
//if (err) { return next(err); }
/*if (!user) { return res.json(filterUser(user)); }
req.logIn(user, function(err) {
if ( err ) { return next(err); }
return res.json(filterUser(user));
});*/
}
//passport.authenticate("deengo-auth", authenticationFailed)(req, res, next);
return null;
},
logout: function(req, res, next) {
req.logout();
res.send(204);
}
};
module.exports = security;
lib/DeengoStrategy.js
var util = require('util');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var BearerStrategy = require('passport-http-bearer').Strategy;
var rest = require('request');
function DeengoRestStrategy(authorize_url, access_token, apiKey, secretKey, scopereq) {
this.authorize_url = authorize_url;
this.access_token = access_token;
this.apiKey = apiKey;
this.secretKey = secretKey;
this.scopereq = secretKey;
this.baseUrl = 'http://localhost:8080/deengo/api/';
// Call the super constructor - passing in our user verification function
// We use the email field for the username
LocalStrategy.call(this, { usernameField: 'email' }, this.verifyUser.bind(this));
// Serialize the user into a string (id) for storing in the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// Deserialize the user from a string (id) into a user (via a cll to REST)
passport.deserializeUser(this.get.bind(this));
// We want this strategy to have a nice name for use by passport, e.g. app.post('/login', passport.authenticate('deengo'));
this.name = DeengoRestStrategy.name;
}
// DeengoRestStrategy inherits from LocalStrategy
util.inherits(DeengoRestStrategy, LocalStrategy);
DeengoRestStrategy.name = "deengo";
// Query the users collection
DeengoRestStrategy.prototype.query = function(query, done) {
query.accessToken = this.accessToken; // Add the apiKey to the passed in query
var request = rest.get(this.baseUrl, { qs: query, json: {} }, function(err, response, body) {
done(err, body);
});
};
// Get a user by id
DeengoRestStrategy.prototype.get = function(id, done) {
var query = { apiKey: this.apiKey };
var request = rest.get(this.baseUrl + id, { qs: query, json: {} }, function(err, response, body) {
done(err, body);
});
};
// Find a user by their email
DeengoRestStrategy.prototype.findByEmail = function(email, done) {
this.query({ q: JSON.stringify({email: email}) }, function(err, result) {
if ( result && result.length === 1 ) {
return done(err, result[0]);
}
done(err, null);
});
};
// Check whether the user passed in is a valid one
DeengoRestStrategy.prototype.verifyUser = function(email, password, done) {
this.findByEmail(email, function(err, user) {
if (!err && user) {
if (user.password !== password) {
user = null;
}
}
done(err, user);
});
};
module.exports = DeengoRestStrategy;
I do not know if I have to use passport-Bearer or not and how to use-it.
Thanks in advance for any help.
Regards,
Eduardo.
I do not know if I have to use passport-Bearer or not and how to use-it.
No. There are other options, such as:
oauth.io
httpProvider + express middleware
Here is an example of how to use passport:
// Express using passport-local
// This code is adaptation of examples/express3 from https://github.com/jaredhanson/passport-local
// configure Express
app.configure(function() {
// ...
app.use(express.session({
// The domain should start with a dot, as this allows the subdomain.
domain: '.app.local',
secret: 'keyboard cat'
}));
// Enable cors.
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
next();
});
// ...
});
app.get('/account', ensureAuthenticated, function(req, res){
// Return the current user's info
res.json(req.user);
});
References
Express + AngularJS Subdomain login