Basic SCIM support

As a first minimal but useful step on the way to SCIM support, allow the dashboard to perform basic SCIM operations against a fixed, statically configured SCIM service provider.

  • Refactor the dashboard source code to facilitate adding SCIM features. Code dealing with users is a bit scattered now, this should be centralized so it's obvious where to add the scim hooks.

    • It seems the right place to add the high-level scim calls is in UserService in user_service.py, which is then the place for high-level user operations.
    • Some code should be moved from users.py::delete to user_service.py. Right now, deleting a user from the CLI only calls KratosUser.delete, and fails to call UserService.delete_user, which deletes the app roles. Maybe confirm this in practice?
    • CLI user functions now call KratosUser directly, but they should go through UserService instead.
  • Extend the dashboard database to store app-internal user IDs (necessary for SCIM protocol). We already have the AppRole model that's a row per user per app, so we can add to that. Also add a field to record SCIM provisioning status, maybe also datetime of last provisioning attempt and (error) message.

  • Add settings for statically configuring a single SCIM service provider.

  • Write a routine for calling SCIM user provisioning. This can be as simple as setting the provisioning status to "SyncNeeded".

  • Write a routine for calling SCIM user deprovisioning. Have to think about how to signal that in the database: maybe "no access" permission in combination with "SyncNeeded", but maybe we don't want to deprovision as soon as access is revoked.

  • Call these new routines on all pertinent events: user creation/deletion, app (un)installation, access right changes.

  • Create a background process that regularly checks the users' provisioning status, and makes the necessary SCIM calls to the configured app.

    • Record last provision attempt time and message.
    • Check for existing user before creating.
    • If user already exists but provisioning is requested, do a PUT to replace/update. Usually we can find the existing user by its externalId (at least for Nextcloud). Users that were created before SCIM was introduced will not have an externalId attribute set, so in that case we need to match based on the userName and/or email address.
    • Disable the user when deprovisioning is requested. There is no dedicated SCIM operation for disabling, but we can set the active attribute to false and hope that the nextcloud SCIM app does the right thing with that.
    • Get relevant user details (name, email address) from Kratos.
    • Take admin rights into account when provisioning users, by also updating the admin group via SCIM.
Edited by Arie Peterson
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information