keycloak icon indicating copy to clipboard operation
keycloak copied to clipboard

Ability to configure LDAP Environment Properties

Open jakub-moravec opened this issue 3 years ago • 14 comments

Describe the bug

We have configured LDAP federation for one of our customers, but it doesn't import any users. Please note that the users and the group don't have the same dc part of a qualified name: dc=amer,dc=example,dc=com vs dc=apac,dc=example,dc=com. Are there any restrictions in this regard? Are there any other ways to debug Keycloak LDAP federation besides turning on the trace logs?

(We are pretty experienced with setting up LDAP federation via Keycloak, this is the first big issue we've encountered.)

Here is that trace log from Keycloak:

LdapOperation: searchPaginated
 baseDn: dc=apac,dc=example,dc=com
 filter: (&(&(ObjectClass=user)(|(memberOf=cn=EXAMPLE_USER_GROUP,ou=groups,dc=amer,dc=example,dc=com)))(objectclass=user))
 returningAttrs: [cn, whenChanged, mail, sn, givenName, whenCreated, pwdLastSet, userAccountControl]
 resultSize: 0

The same filter via ldapsearch utility returns expected users:

ldapsearch -x -LLL -H ldaps://ldapserver.amer.example.com:3269 -D "cn=devuser,ou=Service Accounts,dc=amer,dc=example,dc=com" -W -b "dc=apac,dc=example,dc=com" "(&(&(ObjectClass=user)(|(memberOf=cn=EXAMPLE_USER_GROUP,ou=groups,dc=amer,dc=example,dc=com)))(objectclass=user))"

Version

18.0.0

Expected behavior

Users should be imported into Keycloak

Actual behavior

No users are imported

How to Reproduce?

No response

Anything else?

No response

jakub-moravec avatar Aug 03 '22 08:08 jakub-moravec

How do you perform the LDAP search in Keycloak? Since you are searching using dc=apac as the base, which will likely not include the users directly (they would be placed in an OU), the search should be done using a subtree scope. The ldapsearch utility uses the sub scope by default (and can be changed using the -s flag). Please check that Keycloak also tries to perform a subtree search, and not an one-level search.

darius-m avatar Aug 03 '22 16:08 darius-m

@darius-m Thank you for your response. I can confirm, that the Search Scope in Keycloak is set to 'Subtree'. (On a separate note, it would be nice if this was visible from the trace log as well, but that's not important at the moment.)

Here is (anonymized) example of a DN returned by the ldapsearch query:

dn: CN=JohnDoe,OU=Users,OU=Dalaran,DC=apac,DC=example,DC=com

jakub-moravec avatar Aug 05 '22 10:08 jakub-moravec

I think it would be helpful if you could attach a screenshot of your configuration in Keycloak. Please make sure to hide any confidential information using blank rectangles.

Are you using the same directory user to authenticate from Keycloak, or have implemented any ACIs for access in LDAP?

darius-m avatar Aug 05 '22 14:08 darius-m

Hi Darius,

sorry for the delay, our contact person in the customer organization was on vacation. Please find the screenshot attached.

Thanks, Jakub

image

jakub-moravec avatar Aug 17 '22 08:08 jakub-moravec

Not sure how this information should be translated to ldapsearch so you can test it, but please make sure that the following attributes are correct:

  • UUID LDAP attribute - this must be an attribute that Keycloak can use to uniquely identify the user, and must be present in the user representation;
  • User Object Classes - Java classes that are implemented by the objects - in 389ds common values are inetOrgPerson or organizationalPerson. Looking at the ldapsearch that you have provided above, it appears that you used objectclass=user, but set users as the value in Keycloak.

darius-m avatar Aug 17 '22 09:08 darius-m

@jakub-moravec @darius-m I think I found something that might be relevant, but I don't see where in the code it is happening, and I don't know for sure that it would affect all LDAP servers.

I created a Wireshark capture of traffic from Keycloak to an LDAP server (see attached) and I see that the search request is including the ManageDSAIT control.

My case is a very unusual however, because I wrote my own X.500 directory server that supports the real X.500 DAP, but also, secondarily, LDAP. In the X.500 specifications the ManageDSAIT option does something a little different, but similar, to LDAP. This difference in behavior explains exactly why this does not work for Meerkat DSA, but I am not sure why it wouldn't work for you, since you are probably using just a plain ol' LDAP server rather than a full X.500 directory server.

That said, I would try adding -E manageDSAit to your ldapsearch command to see if it stops working. If it no longer works after adding that option, we know that it is because Keycloak is surreptitiously sending the ManageDSAIT control. I hope that helps!

On that note, I'd also like to add that there is no good reason for Keycloak to send the ManageDSAIT control. I think this should be considered a bug / undone, or at least made configurable.

P.S. After a second look, it still appears that my directory server implements the ManageDSAIT control correctly to the specifications, but I think there is actually a bug in the X.500 specifications themselves that the authors may not have foreseen: namely, use of the ManageDSAIT control is going to result in the Search(II) procedure being invoked instead of Search(I) which will only return context prefixes. I just wanted to throw that out there so you don't think there is a bug in Meerkat DSA. :wink:

keycloak-ldap-managedsait.pcapng.zip

JonathanWilbur avatar Sep 05 '22 23:09 JonathanWilbur

Update: I found in the Java standard library where it adds the ManageDSAIT control here: java.naming/com/sun/jndi/ldap/LdapCtx.java. It is called ManageReferralControl in this library just to make it inconvenient for me to find. This is only added automatically if the LDAP client's referral mode (handleReferrals) is set to LdapClient.LDAP_REF_IGNORE, which is the default.

I think this could be made configurable by overriding the request controls in a line after this one: https://github.com/keycloak/keycloak/blob/f789b7997e03f6c474a9329db607ca0a1c51486e/federation/ldap/src/main/java/org/keycloak/storage/ldap/idm/store/ldap/LDAPContextManager.java#L80

The code would look something like:

if (!configOptions.manageDSAIT) {
    ldapContext.setRequestControls(reqCtls); // where reqCtls does NOT include ManageDSAIT.
}

JonathanWilbur avatar Sep 06 '22 03:09 JonathanWilbur

I also just released an update for Meerkat DSA that makes ManageDSAIT work as expected in both LDAP and DAP. I have tested it and I confirm that entries now appear when synchronized.

JonathanWilbur avatar Sep 07 '22 00:09 JonathanWilbur

@darius-m the search doesn't return results even if we narrow down the parameters you mentioned, specifically when using:

  • UUID LDAP = distinguishedName (which we are sure can be used)
  • User Object Classes = user (again, it's confirmed that this class is correct)

With these in place, I can still see the following log message:

LdapOperation: searchPaginated
 baseDn: dc=apac,dc=example,dc=com
 filter: (&(&(ObjectClass=user)(|(memberOf=cn=EXAMPLE_USER_GROUP,ou=groups,dc=amer,dc=example,dc=com)))(objectclass=user))
 returningAttrs: [cn, whenChanged, mail, sn, givenName, whenCreated, pwdLastSet, userAccountControl]
 resultSize: 0

Is there anything that can be done to make the trace log more useful?

@JonathanWilbur thank you for your inputs! I will try to do the test you suggested and update the ticket.

jakub-moravec avatar Sep 08 '22 16:09 jakub-moravec

I was referring to the screenshot you posted, where the User Object Classes field is set to users instead of user. Not sure if the field is used when you specify the filter, however. The tooltip mentions "existing LDAP user records are found just if they contain all those object classes"; because of this, the lookup may actually return some values, but they are additionally filtered by the connector and the result is empty.

darius-m avatar Sep 09 '22 09:09 darius-m

@darius-m it's ok, I understood your comment. We tried with the fixed value, and the result is still the same.

As I asked in my last comment, is there any way how the trace log could be improved to make it possible to identify which configuration is incorrect? We've had similar solution in place when we had our own implementation of LDAP connector (prior to switching to Keycloak).

jakub-moravec avatar Sep 09 '22 13:09 jakub-moravec

@jakub-moravec @darius-m I think I found something that might be relevant, but I don't see where in the code it is happening, and I don't know for sure that it would affect all LDAP servers.

I created a Wireshark capture of traffic from Keycloak to an LDAP server (see attached) and I see that the search request is including the ManageDSAIT control.

My case is a very unusual however, because I wrote my own X.500 directory server that supports the real X.500 DAP, but also, secondarily, LDAP. In the X.500 specifications the ManageDSAIT option does something a little different, but similar, to LDAP. This difference in behavior explains exactly why this does not work for Meerkat DSA, but I am not sure why it wouldn't work for you, since you are probably using just a plain ol' LDAP server rather than a full X.500 directory server.

That said, I would try adding -E manageDSAit to your ldapsearch command to see if it stops working. If it no longer works after adding that option, we know that it is because Keycloak is surreptitiously sending the ManageDSAIT control. I hope that helps!

On that note, I'd also like to add that there is no good reason for Keycloak to send the ManageDSAIT control. I think this should be considered a bug / undone, or at least made configurable.

P.S. After a second look, it still appears that my directory server implements the ManageDSAIT control correctly to the specifications, but I think there is actually a bug in the X.500 specifications themselves that the authors may not have foreseen: namely, use of the ManageDSAIT control is going to result in the Search(II) procedure being invoked instead of Search(I) which will only return context prefixes. I just wanted to throw that out there so you don't think there is a bug in Meerkat DSA. 😉

keycloak-ldap-managedsait.pcapng.zip

@JonathanWilbur This might actually be really the issue, if we add -E manageDSAit to the ldapsearch command, it stops working. If we add -M manageDSAit instead, though, it still works.

Keycloak team, is there any way how we could configure Keycloak not to use this flag, or use -M instead? (At least for testing now.)

jakub-moravec avatar Oct 17 '22 15:10 jakub-moravec

Hi, Keycloak team, is there any update on this topic? Thank you!

Keycloak team, is there any way how we could configure Keycloak not to use this flag, or use -M instead? (At least for testing now.)

jakub-moravec avatar Nov 16 '22 14:11 jakub-moravec

I can confirm this behaviour. ManageDSAIT is forced by JDK when Context.REFERRAL is set to ignore which happens to be the default value [1]. Keycloak has no option to override this value, thus this is an enhancement request.

It is unlikely that this will be addressed in the legacy store but it should be counted on in the new LDAP storage.

Dev note: This value is possible to override using jndi.properties file placed in a root-level classpath. [2]

[1] https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html [2] https://docs.oracle.com/javase/jndi/tutorial/beyond/env/source.html

hmlnarik avatar Feb 17 '23 14:02 hmlnarik

Hi All,

As per this https://github.com/keycloak/keycloak/pull/24852 (description), they have provided an option to switch between ignore and follow (Referral Property) However, I'm unable to find any such option on the Keycloak GUI. Any suggestions?

Thanks.

guptakaran27 avatar May 24 '24 02:05 guptakaran27