Práctica: Passport y LocalStrategy
Objetivo:
- El servidor proveído por el plugin (sea
iaas
oheroku
) deberá autenticar al lector del libro usandoLocalStrategy
.- El uso de la
LocalStrategy
para autenticación debería ser opcional - Se supone que se guarda la información sobre los usuarios
{login, name, password (encrypted)}
que pueden acceder al libro en un fichero JSON. - Añada una ruta al servidor
/login/password
para que el usuario pueda cambiar la password. En esta ruta se despliega una vista con un formulario que permite al lector cambiar la clave - En el caso de Heroku la volatilidad de la máquina virtual hace que esta solución tenga problemas. Se pueden hacer los cambios permanentes asegurandose que los cambios son añadidos y empujados al repo de Heroku o mas general, guardándo el fichero de claves en algún servicio privado externo (dropbox, google-drive, github, ...) al que se accede vía la correspondiente API
- El uso de la
Ejemplos
Express 4.x app using Passport for authentication with username and password
- Express 4.x app using Passport for authentication with username and password
- Gestión de Sesiones HTTP
- express-session: npm providing simple session middleware for Express
- Understanding passport.js authentication flow (2013)
- Passport exposes a logout() function on req (also aliased as logOut())
- connect-ensure-login: npm Login session ensuring middleware for Connect and Express
- StackOverflow: How to know if user is logged in with passport.js?
- process.nextTick(callback[, ...args])
Ejemplo de uso de inquirer
'use strict';
var inquirer = require('inquirer');
var questions = [
{
type: 'input',
name: 'first_name',
message: 'What\'s your first name'
},
{
type: 'input',
name: 'last_name',
message: 'What\'s your last name',
default: function () {
return 'Doe';
}
},
{
type: 'input',
name: 'phone',
message: 'What\'s your phone number',
validate: function (value) {
var pass = value.match(/^\d+$/i);
if (pass) {
return true;
}
return 'Please enter a valid phone number';
}
}
];
inquirer.prompt(questions).then(function (answers) {
console.log(JSON.stringify(answers, null, ' '));
});
Ejemplo de ejecución:
[~/local/src/javascript/learning/use-credential(master)]$ node input.js
? What's your first name Casiano
? What's your last name Doe
? What's your phone number 111222
{
"first_name": "Casiano",
"last_name": "Doe",
"phone": "111222"
}
Ejemplo de uso de credential
e inquirer
var inquirer = require('inquirer');
var credential = require('credential'),
pw = credential(),
pass = 'chuchu';
pw.hash(pass, function (err, hash) {
if (err) { throw err; }
console.log('Store the password hash:\n', hash);
var questions = [{ message: "Enter your password", type: 'password', name: 'password'}];
inquirer.prompt(questions).then(function (userInput) {
console.log(userInput);
var userPass = userInput.password;
console.log(userPass);
pw.verify(hash, userPass, function (err, isValid) {
var msg;
if (err) { throw err; }
msg = isValid ? 'Passwords match!' : 'Wrong password.';
console.log(msg);
});
});
});
El resultado de una ejecución es parecido a este:
[~/local/src/javascript/learning/use-credential(master)]$ node hash.js
Store the password hash:
{
"hash":"lFPjexO2wJKgliHvoGC4hTdrb6PbwZfKskhY9DP0GA2sHS8BfkZel0JlQ4YNNKvykDox7Bwwpvdx6Pxic84L6Oby",
"salt":"gQ+LdSLI5Qxx9owI/ulxd/Qn5uiBfkEof1UzUCWCT8FJCA7LsCZSzn4fMxB/Lb+grqRBwPA24tE5MtKyw49PnfPo",
"keyLength":66,
"hashMethod":"pbkdf2",
"iterations":340230
}
? Enter your password ******
{ password: 'chuchu' }
chuchu
Passwords match!
Ejemplo de uso de bcrypt-nodejs
Creemos un programa como este:
[~/local/src/javascript/learning/use-credential(master)]$ cat use-bcrypt.js
// Synchronous
var bcrypt = require("bcrypt-nodejs");
/*
* hashSync(data, salt)
- data - [REQUIRED] - the data to be encrypted.
- salt - [REQUIRED] - the salt to be used in encryption.
*/
var hash = bcrypt.hashSync("bacon");
/*
* compareSync(data, encrypted)
- data - [REQUIRED] - data to compare.
- encrypted - [REQUIRED] - data to be compared to.
*/
var ra = bcrypt.compareSync("bacon", hash); // true
console.log(ra);
var wa = bcrypt.compareSync("veggies", hash); // false
console.log(wa);
// Asynchronous
/*
* hash(data, salt, progress, cb)
- data - [REQUIRED] - the data to be encrypted.
- salt - [REQUIRED] - the salt to be used to hash the password.
- progress - a callback to be called during the hash calculation to signify progress
- callback - [REQUIRED] - a callback to be fired once the data has been encrypted.
- error - First parameter to the callback detailing any errors.
- result - Second parameter to the callback providing the encrypted form.
*/
bcrypt.hash("bacon", null, null, function(err, hash) {
/*
* compare(data, encrypted, cb)
- data - [REQUIRED] - data to compare.
- encrypted - [REQUIRED] - data to be compared to.
- callback - [REQUIRED] - a callback to be fired once the data has been compared.
- error - First parameter to the callback detailing any errors.
- result - Second parameter to the callback providing whether the data and encrypted forms match [true | false].
*/
bcrypt.compare("bacon", hash, function(err, res) {
console.log(res); // res == true
});
bcrypt.compare("veggies", hash, function(err, res) {
console.log(res); // res = false
});
});
Ejecución:
[~/local/src/javascript/learning/use-credential(master)]$ node use-bcrypt.js
true
false
true
false
OAuth y Passport
Hashing para guardar las claves
- credential npm module: Easy password hashing and verification in Node. Protects against brute force, rainbow tables, and timing attacks.
- bcrypt: A bcrypt library for NodeJS.
- bcrypt-nodejs: A native JS bcrypt library for NodeJS
Lecturas desde STDIN
- inquirer: Inquirer.js strives to be an easily embeddable and beautiful command line interface for Node.js (and perhaps the "CLI Xanadu").
- read: npm module para leer passwords
Sistemas de Almacenamiento en la Nube
Dropbox
var Dropbox = require('dropbox');
var fs = require('fs');
var prompt = require('prompt');
prompt.start();
prompt.get({
properties: {
accessToken: {
description: 'Please enter an API V2 access token'
},
sharedLink: {
description: 'Please enter a shared link to a file'
}
}
}, function (error, result) {
var dbx = new Dropbox({ accessToken: result.accessToken });
dbx.sharingGetSharedLinkFile({ url: result.sharedLink })
.then(function (data) {
fs.writeFile(data.name, data.fileBinary, 'binary', function (err) {
if (err) { throw err; }
console.log('File: ' + data.name + ' saved.');
});
})
.catch(function (err) {
throw err;
});
});
-
var Dropbox = require('dropbox'); var fs = require('fs'); var path = require('path'); var prompt = require('prompt'); prompt.start(); prompt.get({ properties: { accessToken: { description: 'Please enter an API V2 access token' } } }, function (error, result) { var dbx = new Dropbox({ accessToken: result.accessToken }); fs.readFile(path.join(__dirname, '/basic.js'), 'utf8', function (err, contents) { if (err) { console.log('Error: ', err); } // This uploads basic.js to the root of your dropbox dbx.filesUpload({ path: '/basic.js', contents: contents }) .then(function (response) { console.log(response); }) .catch(function (err) { console.log(err); }); }); });
Ejemplos en el browser To run the examples in your development environment:
- Get a token: click the "Get Token" button on the top right and copy the token
- Clone this repo
- Run
npm install
- From the root of your repository, start the development server with
npm start
. - Point your browser to http://0.0.0.0:8080/
- Este otro módulo node-dropbox: A simple Dropbox API client for node.js no parece muy actualizado