-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Make sure LDAP connections are released when closing sessions #39197
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
Conversation
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.
Unreported flaky test detected, please review
Unreported flaky test detectedIf the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR. org.keycloak.testsuite.webauthn.account.WebAuthnSigningInTest#setUpLinksTestKeycloak CI - WebAuthn IT (firefox)
|
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.
Looking at this change, the behavior of this change is to capture LDAP contexts and close them at the end of this request.
Previously one was supposed to use try-with-resources and closing those resources when no longer needed.
With the implementation suggested here, a single request might acquire multiple contexts for example for multiple queries, it will acquire multiple of those contexts and then release them at the end. Depending the work being performed, this could acquire several contexts for a single LDAP server.
So to fix this bug, I suggest to hunt down where the missing close()
call is. For an enhancement in a future release, I'd say this approach with a transaction is simpler to handle. Still it is missing a functionality to reuse the connection within the same request. And one would need clean up the existing code which is using try-with-resources a lot.
I'm happy to discuss both this change and a the future enhancement which IMHO should be two different PRs.
@ahus1 I don't quite follow what you are proposing here. There is a connection pool behind the scenes and we just need to make sure they are released when processing streams during the response phase. This fix is specifically to this phase of the request lifetime. Can you please elaborate more? |
@pedroigor - please have a look at this approach which uses a closing stream to close the query at the end: pedroigor#17 I debugged it locally, and found that there is exactly one context opened and one closed. I think this aligns better with the concepts that the code could ensure that the query should always be closed. |
Not to muddy things, but wanted to share also this approach: https://github.com/keycloak/keycloak/compare/main...shawkins:iss38660?expand=1 Where we scope the contexts to the session per LDAPConfig. The observation is that each resue of an initialcontext, even from the pool, if it's an SSL connection that seems to have a cost in the milliseconds. I was chatting with @pedroigor about this, so I know that it may not be desirable for a fix, but something to consider for longer term. |
Closes keycloak#38660 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
@ahus1 I think your approach is more error-prone than just making sure we have the context closed whenever creating it. Much cleaner IMO, and easy to track resource clean up for LDAP. But I'm not hard on it, please let me know if you really want your solution and I'll update the PR. In the future, I also see we moving the initialization code currently in @shawkins +1 for what you are proposing as a follow-up. We know there are other things in LDAP that we need to improve we should also consider what you are proposing here. I also changed the PR to use |
@pedroigor - I'd say that closing the context when we are closing the stream is the smaller change to fix the bug at hand to backport it to 26.2. It also ensures that close is only called once on each context. Going forward in 26.3, I'd like to see @shawkins' proposed change, as it returns the same instance when you call it with the same properties. With that change in place, we could gradually remove all the try-with-resources and manually closing contexts from 26.3 or 26.4, and rely on the cleanup of the contexts at the end of the transaction. |
It would be a little simpler to just have this handling in the LDAPContextManager.create method - before returning the LDAPContextManager, just enlist its close. A related change is that the LDAPContextManager.close method should clear the fields, not just close them. This will keep the footprint of the LDAPContextManager associated with the Session as small as possible - alternatively you could make sure the LDAPContextManager instances are removed from the Session on close. I don't fully know the usage pattern with LDAP, but my understanding is that you could have a request that is repeatedly using / closing LDAPContextManagers. |
Yes, but isn't better to encapsulate this within a specific class? Like I said, that would also help to simplify code later by moving initialization code to this new class. AFAIK, the See, I'm happy to have more (smart) people involved in reviewing the LDAP provider but I think we should do that as a follow-up and try to fix this specific problem now. But if you think we should change the approach completely, please let me know, and I'll update the PR. |
Agree, but we need to be careful and make sure reusing LDAP contexts is safe, considering how the LDAP provider is implemented. Also, note that most of the time, mainly for searches like this PR is trying to fix, you have a single ldap context per workerthread/session/request. Another reason why I think we can do this as a follow-up. |
I'm not sure what longer term changes you have in mind, but it seems simpler / better to do: The only concers here are
And of course there's nothing wrong with making a change like this, or the one you are proposing, for safety along with the change proposed by @ahus1 |
Regardless the middle/long-term plans we have for LDAP, I prefer encapsulating this logic and make sure whenever creating an LDAP context we don't forget binding it to the session.
How many instances of
We don't trust/respect the contract already. See https://github.com/keycloak/keycloak/blob/main/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java#L1132. I'm telling you, LDAP is an area that really deserves a review and we have plans to go over it very soon once we start the SCIM work, which will also involve rethinking the User Storage SPI.
Can you please agree then to move forward with this proposal? If you want to create issues for core-iam team to discuss in more detail other parts of LDAP, we are open to starting to discuss them. |
I'm failing to see how it is less encapsulated - the only place we're creating an LdapContext is LDAPContextManager.
That's what I was trying to confirm with you - in the case of search you seem to be indicating that only a single instance of an LDAPContextManager is created / used, but for other operations you may, even for the same LDAPConfig, create and use multiple LDAPContextManager if I understand correctly. Since I don't know how many of these that could be (or correspondingly how many references to LdapContexts), it makes sense to me to accumulate as little state as possible on the Session.
You don't need my approval to move forward. I'm coming at this with a set of fresh eyes - but my impressions and concerns may not be valid.
Sounds good. |
For me, having a In fact, the
|
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.
Approving based on @sguilhen's review
Closes #38660