-
Notifications
You must be signed in to change notification settings - Fork 6.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes a NullPointerException after import validation #20151
Fixes a NullPointerException after import validation #20151
Conversation
da39ded
to
0b6248c
Compare
@@ -340,7 +340,7 @@ public UserModel getUserByEmail(RealmModel realm, String email) { | |||
if (user != null) { | |||
user = importValidation(realm, user); | |||
// Case when email was changed directly in the userStorage and doesn't correspond anymore to the email from local DB | |||
if (email.equalsIgnoreCase(user.getEmail())) { | |||
if (user != null && email.equalsIgnoreCase(user.getEmail())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be correct to return null
here, if importValidation()
returns null
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I missed this question before. I don't think we want to return null
in that case. If importValidation
returns null
it means the user from Keycloak database is invalid and was removed. Returning null
in that situation would mean we say Keycloak does not know the user by this email, however, this is not true and it can be still present in an external provider. We need to query the user again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But that's what I mean, if importValidation
returns null
we return user
which is set to null
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I wrote, we DO NOT want to return null
when validation fails, because some provider may still contain the user.
For example:
- Some provider contains
user1
and it is synced to KC DB - The
user1
is changed in that provider (Keycloak DB is not updated). - If we query this user by email, the validation will fail because the user was changed
- Returning
null
in that case would be wrong because the provider still contains the user. We need to reload the user from the provider (or any other provider knowing user by that email).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the PR @havarnov! Can you please also create some tests for this? I believe the best class to place this is: https://github.com/keycloak/keycloak/blob/main/testsuite/model/src/test/java/org/keycloak/testsuite/model/user/UserSyncTest.java
What we need is:
- Create a user in LDAP
- Load the user by email (imports user to KC database)
- Remove the user from LDAP only
- Assert no exception is thrown and no user was returned
@havarnov Thank you for the PR. Will you be able to add the missing test anytime soon? I can offer more guidance if needed. |
@martin-kanis sry, I've been busy with other stuff. I'll see if I can make it this week! I do have one comment I'd like some feedback on, though: https://github.com/keycloak/keycloak/pull/20151/files#r1184988078 |
I'm having issues running the tests locally. Is there some kind of setup I'm missing maybe?
|
You need to enable some profile in order to have these providers on class path. Try to run the test with |
@mhajas I'm sry, but I can't get the
The actual test fails with:
Is there any dependencies I'm missing, e.g. start a specific container or something? |
No, it should work out of the box. It seems you are doing the correct thing. Have you done any changes to the |
0b6248c
to
64794ba
Compare
No changes to |
I was able to reproduce it @havarnov. It seems there is a bug in the test class. We are not cleaning the LDAP users properly between test methods and it is failing. It was not caught by the CI because for some reason the test passes for second attempt when we use To workaround this, you can run only one test within test class. For example:
this way it passes. I will let you know once I resolve this. |
@mhajas thanks both the work-around and your PR worked for me :D |
If the import validation (when getting a user by email) returns null, indicating that the user entity should be removed from local storage, an email equality check results in a NullPointerException. This commit fixes this issue by explicitly checking for null. Closes keycloak#20150
64794ba
to
64a5295
Compare
@mhajas I've now added a test that fails if the fix is not applied. But, I'm not totally sure why I need the two calls to |
…n it is removed from LDAP Signed-off-by: Michal Hajas <mhajas@redhat.com>
@havarnov We probably don't need to do synchronization at all in this test. I updated the test a little bit. Could you please have a look at whether it makes sense? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution @havarnov
If the import validation (when getting a user by email) returns null, indicating that the user entity should be removed from local storage, an email equality check results in a NullPointerException.
This commit fixes this issue by explicitly checking for null.
Closes #20150