nextcloud / user_oidc

OIDC connect user backend for Nextcloud
GNU Affero General Public License v3.0
76 stars 30 forks source link

migrate local NextCloud user to OIDC #565

Open patzm opened 1 year ago

patzm commented 1 year ago

It is a common use cases that self-hosted environments grow: in features but also from simple to complex. Hence it is likely that a NextCloud instance is first set up with local user management (by NextCloud natively). Maybe later, an authentication server gets mixed in, and here we are: let's use user_oidc for that.

Question: how can one migrate the local users to the OIDC provider?

With vanilla settings, user_oidc always creates a new user, even if the email of a NextCloud user and user_oidc-provided user match.

What I tried: Example: my NextCloud user has the username foo. user_oidc is configured like this: image I.e. it knows which username the authentication server (Keycloak in my case) uses: username. Logging in now, doesn't create a new user, but directly fails:

"Failed to provision user"

Would it be possible to merge accounts then?

s3lph commented 1 year ago

I migrated an instance I'm maintaining from LDAP to OIDC just last week. Basically it boiled down to:

Since in my case the users in question came from the user_ldap backend rather than local, I simply ran a occ app:disable user_ldap to prevent conflicts between LDAP and OIDC users. The LDAP users were still around in the oc_ldap_user_mapping table, they were just no longer visible to Nextcloud. I then copied over all the users with a single INSERT ... SELECT.

I'm not sure whether this works with internal users as well, but I'd probably try the following approach:

DISCLAIMER: This is entirely untested and is just my (hopefully sufficiently) "educated guess" - BACKUP YOUR DATABASE!

  1. occ maintenance:mode --on
  2. Backup the database: mysqldump nextcloud > nextcloud.sql (I'm assuming MySQL/MariaDB in this entire thing)
  3. mysql nextcloud
  4. Copy the users from localto OIDC (though you may want to keep your local admins local):
     INSERT IGNORE INTO oc_user_oidc (user_id, display_name)
       SELECT uid, displayname FROM oc_users
       WHERE uid <> 'root'; -- or whatever your local instance admin is called
  5. Clear out the internal user database:
    CREATE TABLE users_migration_backup AS SELECT * FROM oc_users;
    DELETE FROM oc_users WHERE uid <> 'root'; -- again, substitute with your local admin user(s)
  6. occ maintenance:mode --off
  7. Test login and whether all your data - including in all apps - is still there. Also check group memberships.
  8. If everything turns out ok, you MAY choose to DROP TABLE users_migration_backup, but I'd just leave it as is for the time being

Again: Back up your database before you try this!

yavorivanov-cw commented 5 months ago

I migrated an instance I'm maintaining from LDAP to OIDC just last week. Basically it boiled down to:

* Disable unique user ids in the OIDC provider config

* Make sure the usernames are identical

* Add all users you want to migrate to the `oc_user_oidc` table.

Since in my case the users in question came from the user_ldap backend rather than local, I simply ran a occ app:disable user_ldap to prevent conflicts between LDAP and OIDC users. The LDAP users were still around in the oc_ldap_user_mapping table, they were just no longer visible to Nextcloud. I then copied over all the users with a single INSERT ... SELECT.

I'm not sure whether this works with internal users as well, but I'd probably try the following approach:

DISCLAIMER: This is entirely untested and is just my (hopefully sufficiently) "educated guess" - BACKUP YOUR DATABASE!

1. `occ maintenance:mode --on`

2. Backup the database: `mysqldump nextcloud > nextcloud.sql` (I'm assuming MySQL/MariaDB in this entire thing)

3. `mysql nextcloud`

4. Copy the users from localto OIDC (though you may want to keep your local admins local):
   ```sql
   INSERT IGNORE INTO oc_user_oidc (user_id, display_name)
     SELECT uid, displayname FROM oc_users
     WHERE uid <> 'root'; -- or whatever your local instance admin is called
   ```

5. Clear out the internal user database:
   ```sql
   CREATE TABLE users_migration_backup AS SELECT * FROM oc_users;
   DELETE FROM oc_users WHERE uid <> 'root'; -- again, substitute with your local admin user(s)
   ```

6. `occ maintenance:mode --off`

7. Test login and whether all your data - including in all apps - is still there. Also check group memberships.

8. If everything turns out ok, you MAY choose to `DROP TABLE users_migration_backup`, but I'd just leave it as is for the time being

Again: Back up your database before you try this!

We want to achieve the same ldap -> oidc but the owncloud_name in the oc_ldap_user_mapping table are looking like that: 3e43ac46-500e-103c-9713-95c70e467341 and the oidc user_id in oc_user_oidc table is john.doe.

JeffAlyanak commented 3 months ago

@yavorivanov-cw

In your OIDC provider you should be able to set 3e43ac46-500e-103c-9713-95c70e467341 to be the value for a user attribute that you can then map on the Nextcloud side.

For example, in my case I created the attribute uidNumber which contained the same UID that my old LDAP provider used as a UID: Screenshot_20240328_154505

yavorivanov-cw commented 3 months ago

@yavorivanov-cw

In your OIDC provider you should be able to set 3e43ac46-500e-103c-9713-95c70e467341 to be the value for a user attribute that you can then map on the Nextcloud side.

For example, in my case I created the attribute uidNumber which contained the same UID that my old LDAP provider used as a UID: Screenshot_20240328_154505

Thanks for the reply, but setting this for each user is to much, as this value is not present in LDAP and is just generated by nextcloud or the ldap app.

JeffAlyanak commented 3 months ago

@yavorivanov-cw Thanks for the reply, but setting this for each user is to much, as this value is not present in LDAP and is just generated by nextcloud or the ldap app.

The uid for each user came from my LDAP (FreeIPA) and was also available in the oc_ldap_user_mapping table, so I didn't need to manually set a value for each user.

I had too many users to manually set these all, so I just used the API for my OIDC provider (Authentik) to set that attribute for each user.

mejo- commented 1 month ago

"Failed to provision user"

In case others stumble upon this. Keycloak per default doesn't provide a username attribute. You probably want to set User ID mapping to preferred_username instead. This worked in my case. That way OIDC users were successfully mapped to the existing users on the instance.