Passer au contenu principal
Le script Change Password implémente la fonction définie pour modifier le mot de passe de l’utilisateur spécifié dans la base de données externe. Nous recommandons de nommer cette fonction changePassword. Ce script est utilisé uniquement dans un scénario d’authentification hérité et il est requis si vous souhaitez modifier le mot de passe d’un utilisateur dans la base de données externe. Il s’exécute lorsqu’un utilisateur effectue un processus de réinitialisation du mot de passe, ou lorsqu’un processus de modification du mot de passe est lancé à partir d’ ou de l’Auth0 .

Fonction ChangePassword

La fonction changePassword doit :
  • Mettre à jour le mot de passe de l’utilisateur dans la base de données externe.
  • Retourner true (ou un objet contenant la propriété last_password_reset) si l’opération de changement de mot de passe a réussi. Si la propriété last_password_reset est présente dans l’objet, sa valeur sera mise à jour dans le profil de l’utilisateur.
  • Retourner false si l’opération de changement de mot de passe a échoué.
  • Retourner une erreur si la base de données externe est inaccessible.

Définition

La fonction changePassword accepte trois paramètres et renvoie une fonction callback :
changePassword(email, newPassword, callback): function
ParamètreTypeDescription
emailStringAdresse de courriel de l’utilisateur dans Auth0 et dans la base de données externe.
newPasswordStringValeur à définir comme nouveau mot de passe de l’utilisateur dans la base de données externe. Cette valeur est envoyée en texte brut à la fonction et devrait être chiffrée avant d’être envoyée à la base de données externe.
callbackFunctionUtilisée pour transmettre des données ou le résultat d’une opération dans le pipeline.

Exemple

Voici un exemple en pseudo-JavaScript montrant comment vous pourriez implémenter la fonction changePassword. Pour des exemples propres à des langages précis, consultez Exemples de scripts par langage.
function changePassword(email, newPassword, callback) {
  // Hacher le mot de passe fourni 
  let hashedPassword = hash(newPassword);

  // Préparer l'appel API
  let options = {
    url: "https://example.com/api/users",
    body: {
      email: email,
      password: hashedPassword
    }
  };

  // Appeler l'API
  send(options, err => {
    if (err && err.id == "FAIL_CHANGE_PASSWORD") {
      // Retourner false dans le rappel si le changement de mot de passe a échoué
      return callback(null, false);
    } else if (err) {
      // Retourner une erreur dans le rappel si une autre erreur s'est produite
      return callback(new Error("My custom error message.");
    } else {
      // Retourner true dans le rappel si l'opération de changement de mot de passe a réussi
      return callback(null, true);

      // Ou retourner un objet contenant la propriété `last_password_reset` 
      // si l'opération de changement de mot de passe a réussi.
      // Si la propriété `last_password_reset` est présente dans l'objet,
      // elle sera mise à jour dans le profil de l'utilisateur.
      return callback(null, { "last_password_reset": Date.now() });
    }
  });
}

Chiffrement

Évitez de journaliser, de stocker ou de transmettre le mot de passe sous forme non chiffrée.
Pour éviter toute fuite potentielle de données, chiffrez la valeur du mot de passe à l’aide d’une bibliothèque de hachage cryptographique comme bcrypt.

Exemple

bcrypt.hash(password, 10, function (err, hash) {
    if (err) {
        return callback(err);
    } else {
        // Retourner le mot de passe haché
    }
});

Fonction callback

La fonction callback accepte deux paramètres et permet de transmettre des données d’erreur ou d’indiquer le résultat de l’opération.

Définition

callback(error, operationResult | resultObj): function
ParamètreTypeObligatoireDescription
errorObjectObligatoireContient les données d’erreur.
operationResultBooleanFacultatifIndique le résultat de l’opération de changement de mot de passe.
resultObjObjectFacultatifIndique que l’opération de changement de mot de passe a réussi. Si la propriété last_password_reset est présente, elle sera mise à jour sur le profil de l’utilisateur.

Retourner un succès

Si l’opération de changement de mot de passe a réussi, retournez la fonction callback en passant une valeur null pour le paramètre error et une valeur true pour le paramètre operationResult.

Exemple

return callback(null, true);

Renvoyer une réussite et mettre à jour l’attribut last_password_reset

Si l’opération de changement de mot de passe réussit, appelez la fonction callback en transmettant une valeur null pour le paramètre error et une valeur d’objet pour le paramètre profile. Si l’attribut last_password_reset est fourni dans l’objet, il sera mis à jour dans le profil de l’utilisateur.

Exemple

return callback(null, { "last_password_reset": Date.now() });

Retourner un échec

Si l’opération de changement de mot de passe a échoué, appelez la fonction callback en passant une valeur null comme paramètre error et une valeur false comme paramètre operationResult.

Exemple

return callback(null, false);

Renvoyer une erreur

Si une erreur se produit, appelez la fonction callback et transmettez les renseignements sur l’erreur pertinents dans le paramètre error.

Exemple

return callback(new Error("My custom error message."));

Exemples de scripts par langage

Auth0 fournit des scripts d’exemple pour les langages et technologies suivants :

JavaScript

function changePassword(email, newPassword, callback) {
  // Ce script doit modifier le mot de passe stocké pour l'utilisateur actuel dans votre
  // base de données. Il est exécuté lorsque l'utilisateur clique sur le lien de confirmation
  // après une demande de réinitialisation de mot de passe.
  // Le contenu et le comportement des courriels de confirmation de mot de passe peuvent être personnalisés
  // ici : https://manage.auth0.com/#/emails
  // Le paramètre `newPassword` de cette fonction est en texte brut. Il doit être
  // haché/salé pour correspondre à ce qui est stocké dans votre base de données.
  //
  // Ce script peut se terminer de trois façons :
  // 1. Le mot de passe de l'utilisateur a été mis à jour avec succès :
  //     callback(null, true);
  // 2. Le mot de passe de l'utilisateur n'a pas été mis à jour :
  //     callback(null, false);
  // 3. Une erreur s'est produite lors de la tentative d'accès à votre base de données :
  //     callback(new Error("my error message"));
  //
  // Si une erreur est renvoyée, elle sera transmise à la chaîne de requête de la page
  // vers laquelle l'utilisateur est redirigé après avoir cliqué sur le lien de confirmation.
  // Par exemple, renvoyer `callback(new Error("error"))` et rediriger vers
  // https://example.com redirigera vers l'URL suivante :
  //     https://example.com?email=alice%40example.com&message=error&success=false
  const msg = 'Please implement the Change Password script for this database ' +
    'connection at https://manage.auth0.com/#/connections/database';
  return callback(new Error(msg));
}

ASP.NET Membership Provider (MVC3 - Universal Providers)

function changePassword(email, newPassword, callback) {
  var crypto = require('crypto');
  var Connection = require('tedious').Connection;
  var Request = require('tedious').Request;
  var TYPES = require('tedious').TYPES
  var connection = new Connection({
    userName:  'the username',
    password:  'the password',
    server:    'the server',
    options: {
      database:  'the db name',
      // encrypt: true   for Windows Azure enable this
    }
  });
  /**
   * hashPassword
   *
   * Cette fonction crée une version hachée du mot de passe à stocker dans la base de données.
   *
   * @password  {[string]}      le mot de passe saisi par l'utilisateur
   * @return    {[string]}      le mot de passe haché
   */
  function hashPassword(password, salt) {
    // the default implementation uses HMACSHA256 and since Key length is 64
    // and default salt is 16 bytes, Membership will fill the buffer repeating the salt
    var key = Buffer.concat([salt, salt, salt, salt]);
    var hmac = crypto.createHmac('sha256', key);
    hmac.update(Buffer.from(password, 'ucs2'));
    var hashed = hmac.digest('base64');
    return hashed;
  }
  connection.on('debug', function(text) {
      // if you have connection issues, uncomment this to get more detailed info
      //console.log(text);
  }).on('errorMessage', function(text) {
      // this will show any errors when connecting to the SQL database or with the SQL statements
    console.log(JSON.stringify(text));
  });
  connection.on('connect', function (err) {
    if (err) {
      return callback(err);
    }
    updateMembershipUser(email, newPassword, function(err, wasUpdated) {
      if (err) {
        return callback(err); // this will return a 500
      }
      callback(null, wasUpdated);
    });
  });
  function updateMembershipUser(email, newPassword, callback) {
    var salt            = crypto.randomBytes(16);
    var hashedPassword  = hashPassword(newPassword, salt);
    var updateMembership =
      'UPDATE Memberships '+
      'SET Password=@NewPassword, PasswordSalt=@NewSalt, LastPasswordChangedDate=GETDATE() '+
      'WHERE Email=@Email';
    var updateMembershipQuery = new Request(updateMembership, function (membershipErr, membershipCount) {
      if (membershipErr) {
        return callback(membershipErr);
      }
      callback(null, membershipCount > 0);
    });
    updateMembershipQuery.addParameter('NewPassword', TYPES.VarChar, hashedPassword);
    updateMembershipQuery.addParameter('NewSalt',     TYPES.VarChar, salt.toString('base64'));
    updateMembershipQuery.addParameter('Email',       TYPES.VarChar, email);
    connection.execSql(updateMembershipQuery);
  }
}

ASP.NET Membership Provider (MVC4 - Simple Membership)

function changePassword(email, newPassword, callback) {
  var crypto = require('crypto');
  var Connection = require('tedious').Connection;
  var Request = require('tedious').Request;
  var TYPES = require('tedious').TYPES
  var connection = new Connection({
    userName:  'the username',
    password:  'the password',
    server:    'the server',
    options: {
      database:  'the db name',
      // encrypt: true pour Windows Azure, activer ceci
    }
  });
  /**
   * hashPassword
   *
   * Cette fonction hache un mot de passe à l'aide de l'algorithme HMAC SHA256.
   *
   * @password    {[string]}    mot de passe à hacher
   * @salt        {[string]}    sel à utiliser dans le processus de hachage
   * @callback    {[function]}  rappel à appeler après le hachage du mot de passe
   */
  function hashPassword(password, salt, callback) {
    var iterations         = 1000;
    var passwordHashLength = 32;
    crypto.pbkdf2(password, salt, iterations, passwordHashLength, function (err, hashed) {
      if (err) {
        return callback(err);
      }
      var result = Buffer.concat([Buffer.from([0], 1), salt, Buffer.from(hashed, 'binary')]);
      var resultBase64 = result.toString('base64');
      callback(null, resultBase64);
    });
  }
  connection.on('debug', function(text) {
      // si vous avez des problèmes de connexion, décommentez ceci pour obtenir plus d'informations détaillées
      //console.log(text);
  }).on('errorMessage', function(text) {
      // ceci affichera toutes les erreurs lors de la connexion à la base de données SQL ou avec les instructions SQL
    console.log(JSON.stringify(text));
  });
  connection.on('connect', function (err) {
    if (err) {
      return callback(err);
    }
    updateMembershipUser(email, newPassword, function(err, wasUpdated) {
      if (err) {
        return callback(err); // ceci retournera un 500
      }
      callback(null, wasUpdated);
    });
  });
  function findUserId(email, callback) {
    var findUserIdFromEmail =
      'SELECT UserProfile.UserId FROM ' +
      'UserProfile INNER JOIN webpages_Membership ' +
      'ON UserProfile.UserId = webpages_Membership.UserId ' +
      'WHERE UserName = @Email';
    var findUserIdFromEmailQuery = new Request(findUserIdFromEmail, function (err, rowCount, rows) {
      if (err) {
        return callback(err);
      }
      // Aucun enregistrement trouvé avec ce courriel
      if (rowCount < 1) {
        return callback(null, null);
      }
      var userId = rows[0][0].value;
      callback(null, userId);
    });
    findUserIdFromEmailQuery.addParameter('Email', TYPES.VarChar, email);
    connection.execSql(findUserIdFromEmailQuery);
  }
  function updateMembershipUser(email, newPassword, callback) {
    findUserId(email, function (err, userId) {
      if (err) {
        return callback(err);
      }
      if (userId === null) {
        return callback();
      }
      var salt = crypto.randomBytes(16);
      var updateMembership =
        'UPDATE webpages_Membership '+
        'SET Password=@NewPassword, PasswordChangedDate=GETDATE() '+
        'WHERE UserId=@UserId';
      var updateMembershipQuery = new Request(updateMembership, function (err, rowCount) {
        if (err) {
          return callback(err);
        }
        if (rowCount < 1) {
          return callback();
        }
        callback(null, rowCount > 0);
      });
      hashPassword(newPassword, salt, function (err, hashedPassword) {
        if (err) {
          return callback(err);
        }
        updateMembershipQuery.addParameter('NewPassword',   TYPES.VarChar, hashedPassword);
        updateMembershipQuery.addParameter('UserId',        TYPES.VarChar, userId);
        connection.execSql(updateMembershipQuery);
      });
    });
  }
}

MongoDB

function changePassword(email, newPassword, callback) {
  const bcrypt = require('bcrypt');
  const MongoClient = require('mongodb@3.1.4').MongoClient;
  const client = new MongoClient('mongodb://user:pass@mymongoserver.com');
  client.connect(function (err) {
    if (err) return callback(err);
    const db = client.db('db-name');
    const users = db.collection('users');
    bcrypt.hash(newPassword, 10, function (err, hash) {
      if (err) {
        client.close();
        return callback(err);
      }
      users.update({ email: email }, { $set: { password: hash } }, function (err, count) {
        client.close();
        if (err) return callback(err);
        callback(null, count > 0);
      });
    });
  });
}

MySQL

function changePassword(email, newPassword, callback) {
  const mysql = require('mysql');
  const bcrypt = require('bcrypt');
  const connection = mysql({
    host: 'localhost',
    user: 'me',
    password: 'secret',
    database: 'mydb'
  });
  connection.connect();
  const query = 'UPDATE users SET password = ? WHERE email = ?';
  bcrypt.hash(newPassword, 10, function(err, hash) {
    if (err) return callback(err);
    connection.query(query, [ hash, email ], function(err, results) {
      if (err) return callback(err);
      callback(null, results.length > 0);
    });
  });
}

PostgreSQL

function changePassword (email, newPassword, callback) {
  //cet exemple utilise la bibliothèque "pg"
  //plus d'informations ici : https://github.com/brianc/node-postgres
  const bcrypt = require('bcrypt');
  const postgres = require('pg');
  const conString = 'postgres://user:pass@localhost/mydb';
  postgres.connect(conString, function (err, client, done) {
    if (err) return callback(err);
    bcrypt.hash(newPassword, 10, function (err, hash) {
      if (err) return callback(err);
      const query = 'UPDATE users SET password = $1 WHERE email = $2';
      client.query(query, [hash, email], function (err, result) {
        // REMARQUE : appelez toujours `done()` ici pour fermer
        // la connexion à la base de données
        done();
        return callback(err, result && result.rowCount > 0);
      });
    });
  });
}

SQL Server

function changePassword (email, newPassword, callback) {
  //cet exemple utilise la bibliothèque "tedious"
  //plus d'informations ici : http://tediousjs.github.io/tedious/
  const bcrypt = require('bcrypt');
  const sqlserver = require('tedious@1.11.0');
  const Connection = sqlserver.Connection;
  const Request = sqlserver.Request;
  const TYPES = sqlserver.TYPES;
  const connection = new Connection({
    userName:  'test',
    password:  'test',
    server:    'localhost',
    options:  {
      database: 'mydb'
    }
  });
  const query = 'UPDATE dbo.Users SET Password = @NewPassword WHERE Email = @Email';
  connection.on('debug', function(text) {
    console.log(text);
  }).on('errorMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  }).on('infoMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  });
  connection.on('connect', function (err) {
    if (err) return callback(err);
    const request = new Request(query, function (err, rows) {
      if (err) return callback(err);
      callback(null, rows > 0);
    });
    bcrypt.hash(newPassword, 10, function (err, hash) {
      if (err) return callback(err);
      request.addParameter('NewPassword', TYPES.VarChar, hash);
      request.addParameter('Email', TYPES.VarChar, email);
      connection.execSql(request);
    });
  });
}

Windows Azure SQL Database

function changePassword (email, newPassword, callback) {
  //cet exemple utilise la bibliothèque "tedious"
  //plus d'informations ici : http://pekim.github.io/tedious/index.html
  var Connection = require('tedious@1.11.0').Connection;
  var Request = require('tedious@1.11.0').Request;
  var TYPES = require('tedious@1.11.0').TYPES;
  var bcrypt = require('bcrypt');
  var connection = new Connection({
    userName:  'your-user@your-server-id.database.windows.net',
    password:  'the-password',
    server:    'your-server-id.database.windows.net',
    options:  {
      database: 'mydb',
      encrypt:  true
    }
  });
  var query = 'UPDATE dbo.Users SET Password = @NewPassword ' +
    'WHERE Email = @Email';
  connection.on('debug', function(text) {
    // Décommenter la ligne suivante pour activer les messages de débogage
    // console.log(text);
  }).on('errorMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  }).on('infoMessage', function(text) {
    // Décommenter la ligne suivante pour activer les messages d'information
    // console.log(JSON.stringify(text, null, 2));
  });
  connection.on('connect', function (err) {
    if (err) { return callback(err); }
    var request = new Request(query, function (err, rows) {
      if (err) { return callback(err); }
      console.log('rows: ' + rows);
      callback(null, rows > 0);
    });
    bcrypt.hash(newPassword, 10, function (err, hash) {
      if (err) { return callback(err); }
      request.addParameter('NewPassword', TYPES.VarChar, hash);
      request.addParameter('Email', TYPES.VarChar, email);
      connection.execSql(request);
    });
  });
}

En savoir plus