Ajout du SSO après que de nombreux utilisateurs se sont déjà inscrits -- comment les migrer ?

Salut à tous.

Quelle est la bonne façon d’importer tous les utilisateurs existants de Discourse vers intercoin.app depuis Discourse ? Existe-t-il un point de terminaison REST qui renvoie tous les utilisateurs avec leurs mots de passe hachés et leurs sels, entre autres choses ? Quel est le lien vers l’algorithme de hachage sur github ? Je devrai coder de notre côté, pour utiliser le même algorithme de hachage avec le mot de passe et le sel entrés, si le nôtre ne fonctionne pas, afin de permettre à ces personnes de se connecter. Je pense que le point #2 est pertinent chaque fois qu’un utilisateur Discourse active le SSO plus tard (comme nous le faisons), donc le résoudre aiderait également d’autres utilisateurs de Discourse.

2 « J'aime »

Approche intéressante.

Dans user.rb

  def confirm_password?(password)
    return false unless password_hash && salt
    self.password_hash == hash_password(password, salt)
  end

  def hash_password(password, salt)
    raise StandardError.new("le mot de passe est trop long") if password.size > User.max_password_length
    Pbkdf2.hash_password(password, salt, Rails.configuration.pbkdf2_iterations, Rails.configuration.pbkdf2_algorithm)
  end

et le code Pbkdf2 se trouve ici : discourse/lib/pbkdf2.rb at 201228162c277b9833bb2988388553fdbfb39521 · discourse/discourse · GitHub

2 « J'aime »

Excellent ! Quel est maintenant le point de terminaison HTTP que j’appelle pour obtenir toutes les informations utilisateur, y compris le hachage du mot de passe et le sel ?

J’imagine qu’il n’y en a pas un pour servir au grand public (pourquoi faciliter le piratage des gens ?) Alors, que puis-je faire ? Me connecter à la base de données MySQL ? Écrire un plugin Discourse ?

1 « J'aime »

Ce sont essentiellement vos options, oui.

1 « J'aime »

Le schéma de base de données est-il documenté quelque part ?

Comment se connecter à la base de données postgres dans le docker ? Désolé si c’est une question stupide.

1 « J'aime »

J’ai juste parlé à notre équipe, et ils sont d’accord, je suis prêt à payer quelqu’un pour créer un petit plugin Discourse qui exposerait via un endpoint des informations JSON sur un utilisateur, étant donné son adresse e-mail.

J’ai trouvé https://github.com/discourse/discourse/blob/main/app/models/user.rb#L1855 qui a le sel “password_hash” et le nom, le nom d’utilisateur. Mais il n’a pas l’e-mail. Pour cela, je vois user_email discourse/app/models/user_email.rb at main · discourse/discourse · GitHub

Donc, étant donné un e-mail, le plugin recherchera simplement dans la table user_email par l’e-mail, trouvera l’user_id et récupérera la ligne de l’utilisateur, et enverra tous les champs “sûrs”, y compris le sel.

Pour plus de sécurité, les requêtes peuvent être signées via HMAC en utilisant un secret partagé qui peut être fourni au plugin.

Quelqu’un veut-il le faire ? Envoyez-moi un message ou répondez ici et faites-moi savoir comment vous contacter. J’espère que c’est simple (quelques SELECT et une vérification HMAC si le secret a été défini). Nous lirons le JSON.

1 « J'aime »

J’utiliserais simplement le admin/users/list/active.json existant et j’étendrais la réponse avec les mots de passe hachés.

De plus, respectez le mécanisme d’authentification API existant, ne réinventez pas une autre roue.

1 « J'aime »

Vous voulez donc dire que je devrais avoir une chose unique qui importe tous les utilisateurs rejoints avec tous leurs sels et mots de passe ?

Soit, mais cela doit toujours être un plugin, n’est-ce pas ? Ce serait donc formidable si quelqu’un de Discourse pouvait le créer.

1 « J'aime »

J’utiliserais probablement le plugin data explorer pour exporter les informations que vous souhaitez. Ce sera beaucoup plus facile que d’écrire un nouveau plugin.

1 « J'aime »

Comment puis-je connaître cette valeur de configuration ? Quelle est la valeur par défaut, est-elle quelque part dans le code ? @RGJ

root@server:~# cd /var/discourse/
root@server:/var/discourse# ./launcher enter app
x86_64 arch détecté.
root@server:/var/www/discourse# rails c
[1] pry(main)> Rails.configuration.pbkdf2_iterations
=> 64000
[2] pry(main)>

Merci ! OK @RGJ, quelques questions rapides :

La bibliothèque xorcist est juste un XOR de chaînes plus rapide, n’est-ce pas ? Que se passe-t-il si l’un des caractères se retrouve être 0 parce que ‘a’ a été XORé avec ‘a’ – qu’arrive-t-il à cette chaîne ? Les chaînes ne sont-elles pas null-terminées ?

Mon objectif est de porter cela en PHP, donc tout ce que vous pourrez faire pour m’aider (comme me donner des informations sur la façon de le reproduire en PHP) sera très utile.

Aussi, que fait cette ligne ? ret.bytes.map { |b| ("0" + b.to_s(16))[-2..-1] }.join("")

$u = hash_hmac('sha256', $password, $salt . pack('N', 1));
$ret = $u = hash_hmac('sha256', $password, $u);
for ($i=2; $i<$iterations; ++$i) {
  $u = hash_hmac('sha256', $password, $u);
  $ret = ($ret ^ $u);
}
// todo: comprendre ce que fait RUBY sur cette dernière ligne

Est-ce que c’est proche ? Pouvez-vous s’il vous plaît corriger ce code PHP ?

Ceci est une fonction intégrée.

$hash = hash_pbkdf2('sha256', 'YourPassword', 'YourSalt', 64000, 64, false);

En général, les algorithmes de hachage fonctionnent sur des données binaires et le résultat est encodé en hexadécimal ou en Base64 lors de la sortie. Ce n’est donc pas un problème.

1 « J'aime »

Merci beaucoup Richard ! Vous m’avez fait gagner ÉNORMÉMENT de temps par rapport à l’implémentation en PHP userland !

Oui ! J’ai réussi à créer un script qui parcourt tous les utilisateurs de Discourse et les importe avec le hachage de leur phrase secrète sur notre plateforme.

Bientôt, nous pourrons permettre à quiconque possède un forum Discourse d’ajouter également des événements, de la visioconférence, des médias, et plus encore, avec Discourse dans l’onglet « Discuter ». Vous pouvez voir le résultat sur https://intercoin.app

Essentiellement, transformer n’importe quelle installation Discourse en un réseau social moderne à la Facebook. Nous avons travaillé pendant des années sur ces fonctionnalités et maintenant nous voulons les intégrer étroitement avec Discourse et Wordpress également. Ainsi, les gens pourront combiner Wordpress, Discourse et Qbix et auto-héberger leur communauté entière.

Mais il me reste deux problèmes.

  1. Dans Qbix, nous hachons le mot de passe côté client au moins avec sha1(mot de passe + userId) avant de l’envoyer au serveur. Même lorsque c’est https. Nous le faisons pour que le serveur ou tout MITM n’ait JAMAIS le mot de passe, pour le réutiliser sur différents sites. Mais, Discourse envoie simplement le mot de passe au serveur. Nous avons donc dû désactiver ce hachage côté client. Est-il possible de faire quelques itérations de hash_pbkdf2 côté client, et le reste côté serveur ? J’ai essayé et cela ne semble pas correspondre :
php > $password = 'abc';
php > $salt = 'def';
php > $a = hash_pbkdf2('sha256', $password, $salt, 64000, 64, false);
php > $b = hash_pbkdf2('sha256', $password, $salt, 1, 64, false);
php > $c = hash_pbkdf2('sha256', $password, $b, 63999, 64, false);
php > echo $a;
9d7a21ae4113bea06d81e0c486f45ab778bb739f19f7a6a305d8401918a9d8a1
php > echo $c;
f42af6861ebcf8560b027276e0d02ad46502636045486057d81be7c4c4aa630e
  1. Serait-il possible d’utiliser simplement Discourse comme fournisseur SSO, au lieu d’utiliser notre site comme fournisseur SSO ? Alors les hôtes de forums Discourse seraient encore plus susceptibles de l’étendre avec les fonctionnalités Qbix, car la connexion resterait exactement la même, et du côté de Discourse. Facebook, Google, et tout le reste. Existe-t-il une documentation sur le type d’informations que Discourse Connect renvoie en tant que fournisseur SSO à notre site consommateur ? Inclut-il des éléments tels que la photo que nous pouvons télécharger, le prénom, le nom et au moins le nom d’utilisateur ?

Honnêtement, je ne pense pas que la soumission d’un mot de passe via HTTPS par Discourse soit votre plus grand défi de sécurité pour le moment.

Bien sûr. Je pense que vous obtenez la plupart des choses dans le sérialiseur d’utilisateur standard.
Mais si cela ne suffit pas, vous pouvez toujours utiliser l’API pour obtenir plus d’informations de Discourse.

2 « J'aime »

Franchement, je ne pense pas que la soumission d’un mot de passe via HTTPS par Discourse soit votre plus grand défi de sécurité pour le moment.

Mignon. Je vois votre sha1 et je vous baisse votre md5 :slight_smile:

Je vois pourquoi ce pbkdf2 ne fonctionne pas vraiment pour le diviser… le problème est la première ligne :

U1 = PRF(Password, Salt + INT_32_BE(i))
U2 = PRF(Password, U1)
⋮
Uc = PRF(Password, Uc−1)

Des idées pour le diviser, cependant ? Je suppose que je peux simplement utiliser la bibliothèque php pure en userland : pbkdf2/src/PBKDF2.php at master · Spomky-Labs/pbkdf2 · GitHub

Je recommanderais à Discourse de hasher les choses avec un sel (userId fonctionne) avant d’envoyer le mot de passe sur le réseau. Pourquoi pas ? Cela n’a pas à devenir incompatible avec ce que vous stockez dans la base de données actuellement. Faites simplement les 100 premières itérations en Javascript, puis soustrayez 10 de 64000. Vous avez une implémentation personnalisée de toute façon (copiée de rails), donc vous enverriez simplement une variable isHashed, et si elle est vraie, alors faites uniquement les “dernières” 64K-10 étapes.

L’ID utilisateur n’est pas connu avant la connexion, donc cela ne fonctionnera pas…

10 itérations ne sont pas sécurisées, et 63990 itérations sont moins sécurisées que 64000 itérations. Donc, bien que ce soit marginal, il semble que vous remplaciez une méthode sécurisée par deux méthodes moins sécurisées et beaucoup de complexité supplémentaire.

Et quel est le gain réel ?

1 « J'aime »