Skip to content

Federated user disabled when external DB unavailable, never re-enabled #45889

Description

@mruzicka

Before reporting an issue

  • I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

Area

infinispan

Describe the bug

We've implemented a custom user storage provider which reads users from an external DB. The following commits: d65c17e, 54d2451 (in particular the changes in the org.keycloak.storage.UserStorageManager.validateFederatedUser(RealmModel, UserModel) method) cause federated users from the external DB to become disabled when they attempt to log in during a time when the external DB is unavailable (which is the case with our external DB during backups) and remain disabled virtually indefinitely.

The sequence of events leading to this is as follows:

  1. the external DB becomes unavailable
  2. a federated user from the external DB attempts to log in
  3. the imported user validation is performed, but due to a DB error when querying the external DB (and the try/catch block added in the commits referenced above) a read only delegate with the enabled attribute forced to false is created for the user and returned
  4. this read only, disabled delegate is cached in Infinispan

This disabled user remains in the cache even after the external DB becomes available again, making the user effectively disabled and unable to log in until somehow evicted from the cache.

Before the referenced commits, the login attempt during the external DB unavailable window resulted in a failed login attempt but not in the caching of the read only, disabled delegate. In consequence when the external DB became available, the federated users could immediately log in again.

Version

26.5.2

Regression

  • The issue is a regression

Expected behavior

Federated users who attempt to log in when the respective external source (DB) is unavailable become disabled. (This is already the case.)
But they are re-enabled when the external source becomes available again (perhaps with some delay), i.e. do not remain disabled virtually indefinitely as is the case today.

Actual behavior

Federated users who attempt to log in when the respective external source (DB) is unavailable become disabled. (This is already the case.)
These users remain disabled even after the external source becomes available again. The cause of this that the disabled version of the user (created during the external source unavailability) remains cached in Inifinispan and never seems to be evicted (especially for users used for periodic jobs with regular login attempts).

How to Reproduce?

  1. have a custom UserStorageProvider implementing ImportedUserValidation
  2. have the ImportedUserValidation.validate(RealmModel, UserModel) throw an exception under some conditions (e.g. when an external DB is down)
  3. have the cache enabled for the user federation using the custom user storage provider
  4. log in (successfully) as a federated user managed by the custom user storage provider (this is so that a copy of the federated user is stored in the Keycloak's own DB)
  5. stage the conditions such that the validate method is bound to throw the exception (e.g. stop the external database)
  6. attempt to log in as the same user as in 3.
  7. observe that the login attempt fails and the user becomes disabled
  8. stage the conditions such that the validate method is bound to succeed
  9. attempt to log in as the same user as in 3. & 6.
  10. observe that the login attempt fails as the user is still disabled (and remains so virtually indefinitely)

Anything else?

There are workarounds:

  • disable cache for the user federation using the custom user storage provider
  • clear the users cache (e.g. by calling the /admin/realms/<realm name>/clear-user-cache API) to evict the stale disabled users (this is what we currently do)

Metadata

Metadata

Assignees

Type

Fields

No fields configured for bug.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions