nextcloud / user_oidc

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

Hard provisioned user can not be looked up in oidc backend in some cases #898

Open thlehmann-ionos opened 2 months ago

thlehmann-ionos commented 2 months ago

TL;DR: when the provider was configured with unique-uid=1 (default) an ID would be created that is not equal to the ID in Nextcloud's backend and derived from the sub claim.

This would later lead to code not finding the user in the user_oidc backend, i.e. to check whether password authentication is possible.

Steps

Configure and provision

  1. Configure OIDC in the instance config for hard provisioning
  2. Configure the OIDC provider with --unique-uid explicitly or implicitly true (1)
  3. Provision the user in the Nextcloud backend with the ID from the sub claim
  4. Provision the user in the user_oidc backend with the ID from the sub claim Note: user_oidc will add an entry to its user table with a different ID.

Details: how the user was provisioned in Nextcloud

id="<ID as returned by the OIDC provider in the 'sub' claim>"
# other variables omitted

curl \
    -d "userid=${id}" \
    -d "password=" \
    -d "email=${email}" \
    -d "displayName=${display_name}" \
    -d "groups[]=${group}" \
    -H "OCS-APIRequest: true" \
        "http://${AUTH}@localhost:8080/ocs/v1.php/cloud/users"

Details: how user_oidc was configured and provisioned

The addon is configured with:

'user_oidc' => [
  'auto_provision' => false,
  'soft_auto_provision' => false,
],

The provider was configured as:

./occ user_oidc:provider "CLIENT" \
    --clientid="CLIENT" \
    --clientsecret="XXXXXXXXXXXXX" \
    --discoveryuri="DISCOVERY" \
    --scope="SCOPES"

Note: the provider was not configured with --unique-uid=0.

The user was provisioned with:

provider="<provider ID as returned by occ user_oidc:provider>"
id="<ID from the OIDC provider>"
# other variables omitted

curl \
    -D - \
    -X POST \
    -d "providerId=${provider}" \
    -d "userId=${id}" \
    -d "email=${email}" \
    -d "displayName=${display_name}" \
        "http://${AUTH}@localhost:8080/index.php/apps/user_oidc/user"

Why was the user provisioned in Nextcloud's and user_oidc's backend?

The call /apps/user_oidc/user (ApiController->createUser()) will fail at getUserFolder(), which tries to get a user folder from the Nextcloud backend.

Thus, the assumption was that a user has to be provisioned in the Nextcloud backend too.

Login via OIDC

  1. Log user in via the OIDC provider
  2. In the browser console test run or evaluate window.backendAllowsPasswordConfirmation
  3. Observation: the value is true
  4. Wait a couple of hours
  5. Go to settings and try to create an app token
  6. Expected: the token gets created and is displayed
  7. Actual: a password confirmation dialog is displayed (see below)

How this leads to a problem

Later, when the user had logged in, the user manager will query the all known backends (including Nextcloud's user database).

However, it would not be able to find the user in the user_oidc table, because it was generated with a unique ID.

Since the user was not found in the user_oidc backend, Nextcloud will default to its own backend.

Later code will use the "wrong" backend and may mistakenly determine the user could authenticate themself.

Example JsConfigHelper.

password-confirmation-displayed-to-user-logged-in-via-oidc_

Debugging session

Earlier in the request the user would be looked up by the OIDC provider's ID (see type of the user mapper $this and the value of $uid):

oidc-user-mapper-searching-for-idm-user-id_

Later - different from what's shown below - code would use the default Nextcloud backend ($backend) and fail the instanceof IPasswordConfirmationBackend test:

jsconfighelper-testing-whether-the-backend-can-confirm-the-password-not-ok_2

This is how it would turn out if the provider was configured with uniqueUid=0, see how $backend is correct now:

jsconfighelper-testing-whether-the-backend-can-confirm-the-password_

Expectation

  1. the documentation on hard provisioning should be extended to explain how to provision users in the Nextcloud backend correctly
  2. granted the updated documentation does not explain why this would be a user/admin/developer error: possible bug fix of the user_oidc provisioning code depending on a user to be added in the Nextcloud backend
  3. granted the updated documentation does not explain why this would be a user/admin/developer error: user_oidc should not add users with a different ID than was specified through the API (since, as explained above, this may lead to subsequent errors)

The code path during user provisioning should either not exist or there should be documentation how to provision users in Nextcloud correctly when using uniqueUid=1.