Manually moving users from one YunoHost installation to another

:uk:/:us: Message template (english)

My YunoHost server

Hardware: VPS bought online
YunoHost version: 11.1.6.1 (Server A), 11.1.7 (Server B)
I have access to my server : Through SSH (and webadmin)
Are you in a special context or did you perform some particular tweaking on your YunoHost instance ? : yes
If yes, please explain:

  • Server A is an old server running YunoHost 10 which has now been upgraded to 11.
  • Server B is a fresh install of YunoHost, but I exported some users from Server A and imported them to Server B (details below).

Description of my issue

I’m trying to copy a subset of Yunohost users from Server A to Server B using the YunoHost export command.

To get the users across, I exported them from Server A, modified the resulting CSV, and imported them to Server B (expand for details)
  • First, I ran yunohost user export on Server A to generate a CSV file, which I then copied to Server B
  • The users’ primary domain, example.com, is currently pointed at Server A but I’ve added the domain to Server B and am planning to point the domain there once the user migration is done. So I had edit the CSV file to remove other domains like old.example.com which are exclusively for Server A.
  • Finally, I ran yunohost user import to get the users at the other end.

Now I have the users showing up in the control panel, but they don’t have passwords to log in with. Is there a way to copy the passwords across? I don’t need to know the passwords themselves; I just want to move the hashes so users can continue logging in with the same passwords they’re used to.

I took a look at /etc/shadow, but none of the users were listed there, which I realised is probably because the users are being handled by LDAP. So I guess my basic question is: what’s the LDAP equivalet of copying over hashes from /etc/shadow?

I recently migrated a different YunoHost server; that time I did a full backup on the old server followed by a full restore on the new server. In this case I only need to get across a subset of users. I could create a backup of all the users and manually modify it to include the ones I want, but that sounds like a lot of work I’m guessing there’s an easier way to do it by manipulating LDAP directly?


:fr: Modèle de message (français)

Cette version est traduite de l’anglais à l’aide de Google. Toutes mes excuses s’il y a des erreurs !

Mon serveur YunoHost

Matériel: VPS acheté en ligne
Version de YunoHost: 11.1.6.1 (Serveur A), 11.1.7 (Serveur B)
J’ai accès à mon serveur : En SSH (et webadmin)
Êtes-vous dans un contexte particulier ou avez-vous effectué des modificiations particulières sur votre instance ? : oui
Si oui, expliquer:

  • Le serveur A est un ancien serveur exĂ©cutant YunoHost 10 qui a maintenant Ă©tĂ© mis Ă  niveau vers 11.
  • Le serveur B est une nouvelle installation de YunoHost, mais j’ai exportĂ© certains utilisateurs du serveur A et les ai importĂ©s sur le serveur B (dĂ©tails ci-dessous).

Description du problème

Pour transmettre les utilisateurs, je les ai exportés du serveur A, j'ai édité le CSV résultant et je les ai importés sur le serveur B (développez pour plus de détails)
  • Tout d’abord, j’ai exĂ©cutĂ© yunohost user export sur le Serveur A pour gĂ©nĂ©rer un fichier CSV, que j’ai ensuite copiĂ© sur le Serveur B
  • Le domaine principal des utilisateurs, example.com, pointe actuellement vers le Serveur A, mais j’ai ajoutĂ© le domaine au Serveur B et je prĂ©vois d’y pointer le domaine une fois la migration de l’utilisateur terminĂ©e. J’ai donc dĂ» modifier le fichier CSV pour supprimer d’autres domaines tels que old.example.com qui sont exclusivement destinĂ©s au Serveur A.
  • Enfin, j’ai exĂ©cutĂ© la commande yunohost user import pour obtenir les utilisateurs Ă  l’autre bout.

Maintenant, les utilisateurs s’affichent dans le panneau de configuration, mais ils n’ont pas de mot de passe pour se connecter. Existe-t-il un moyen de copier les mots de passe ? Je n’ai pas besoin de connaître les mots de passe eux-mêmes ; Je veux juste déplacer les hachages pour que les utilisateurs puissent continuer à se connecter avec les mêmes mots de passe auxquels ils sont habitués.

J’ai jeté un coup d’œil à /etc/shadow, mais aucun des utilisateurs n’y était répertorié, ce que j’ai réalisé, c’est probablement parce que les utilisateurs sont gérés par LDAP. Donc, je suppose que ma question de base est : quel est l’équivalent LDAP de la copie de hachages depuis /etc/shadow ?

J’ai récemment migré un autre serveur YunoHost ; cette fois, j’ai fait une sauvegarde complète sur l’ancien serveur suivie d’une restauration complète sur le nouveau serveur. Dans ce cas, je n’ai besoin que d’atteindre un sous-ensemble d’utilisateurs. Je pourrais créer une sauvegarde de tous les utilisateurs et la modifier manuellement pour inclure ceux que je veux, mais cela ressemble à beaucoup de travail. Je suppose qu’il existe un moyen plus simple de le faire en manipulant directement LDAP ?

Okay, so after a confusing dive into LDAP I came up with this somewhat hacky but very effective solution!

:information_source: Disclaimer: I’m running this on an empty system (not apps installed yet). I don’t think there will be consequences if there are apps installed, since they all get their passwords from the same place when they support LDAP, but there might be something I’m missing!

Step 0: Make sure the users are imported

I’m assuming you’ve already used yunohost user export on Server 1 to get a CSV file, kept the users you want and deleted the rest, and then imported the users to Server 2 using the modified CSV file.

Step 1: Get the user data

Create a “System Configuration” backup. You only need to back up the “System Configuration; nothing else”.

Extract the resulting .tar and open the conf/ldap/dc=yunohost-dc=org.ldif file inside it. (I think you can also get this by running a slapcat command, but I’m not sure what it is; if someone knows please add it here to make the process simpler!).

Step 2: Extract the password hash

Get the base64-encoded hashed password. To do that, scroll through the LDIF file until you find an entry something like this:

dn: uid=USERNAME,ou=users,dc=yunohost,dc=org
uid: USERNAME
objectClass: mailAccount
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: userPermissionYnh
uidNumber: 123456
displayName: FIRST LAST
userPassword:: 123XYZ123XYZ123XYZ
 ABC789ABC789ABC789
 456456=
gidNumber: 12345
homeDirectory: /home/USERNAME
# ...lots of other lines omitted...

The main thing to look out for is the first dn line:

  • uid should be the username of the user whose password you want
  • ou should be users (not groups for example)

Once you found the record, copy the userPassword. This might span several lines, so remember to convert it to one line and remove all the spaces in between. For example, in this case it would become:

123XYZ123XYZ123XYZABC789ABC789ABC789456456=
^-----------------^-----------------^------------
from 1st line     from 2nd line     from 3rd line

Finally, you will have to decode the base64 to get the actual password hash. This can be done in Python (remember to replace with the actual hash!)

>>> import base64
>>> encoded_pw = '123XYZ123XYZ123XYZABC789ABC789ABC789456456='
>>> pw_hash = base64.b64decode(encoded_pw)
>>> pw_hash
b'{CRYPT}$X$ABCDEF$123DEF678' # actual output will be longer

Ignore the b in the beginning, the part within the quotes is your password hash.

Step 3: Update the user

I’ve written a small Python function for this, but you can also manually enter each command in the terminal. It’s basically hacked together from part of YunoHost’s update_user function in the source code.

It worked when I ran it as root; I haven’t tried from a normal user yet…

# user_update.py
from yunohost.user import user_update

def set_password_from_hash(username, pw_hash):
    from yunohost.utils.ldap import _get_ldap_interface

    ldap = _get_ldap_interface()
    attrs_to_fetch = ["givenName", "sn", "mail", "maildrop", "memberOf"]
    result = ldap.search(
        base="ou=users",
        filter="uid=" + username,
        attrs=attrs_to_fetch
    )

    new_attr_dict = {}
    new_attr_dict["userPassword"] = [pw_hash]

    return ldap.update(f"uid={username},ou=users", new_attr_dict)

You can run it something like this:

>>> from user_update import set_password_from_hash
>>> set_password_from_hash('USERNAME', pw_hash)
True

I didn’t get any errors; I hope you don’t either! :slight_smile:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.