-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Add LDAP groups provider plugin #20157
Conversation
lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/ldap/LdapQuery.java
Outdated
Show resolved
Hide resolved
.../trino-ldap-groups-provider/src/main/java/io/trino/plugin/ldapgroups/LdapGroupsProvider.java
Outdated
Show resolved
Hide resolved
.../trino-ldap-groups-provider/src/main/java/io/trino/plugin/ldapgroups/LdapGroupsProvider.java
Outdated
Show resolved
Hide resolved
...-ldap-groups-provider/src/main/java/io/trino/plugin/ldapgroups/LdapGroupsProviderConfig.java
Outdated
Show resolved
Hide resolved
...ups-provider/src/test/java/io/trino/plugin/ldapgroups/TestLdapGroupsProviderIntegration.java
Outdated
Show resolved
Hide resolved
...trino-ldap-groups-provider/src/main/java/io/trino/plugin/ldapgroups/LdapHighLevelClient.java
Outdated
Show resolved
Hide resolved
...trino-ldap-groups-provider/src/main/java/io/trino/plugin/ldapgroups/LdapHighLevelClient.java
Outdated
Show resolved
Hide resolved
@Praveen2112 Hello! Pinging you in case you missed the updates. Addressed the review comments, please have a look when you can |
This pull request has gone a while without any activity. Tagging the Trino developer relations team: @bitsondatadev @colebow @mosabua |
@mosiac1 Thank you for addressing the comments !! Will take a look at this PR |
82cf890
to
4214d89
Compare
Hello @Praveen2112! I rebased on top of main, split the changes into 3 commits and added tests for the CachingGroupProvider classes. Would really appreciate if you can take a look! |
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.
Instead of mock library - can we use the TestingOpenLdapServer which could provide a accurate behavior.
lib/trino-plugin-toolkit/src/test/java/io/trino/plugin/base/cache/TestCacheConfig.java
Outdated
Show resolved
Hide resolved
...rino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/group/CachingGroupProvider.java
Outdated
Show resolved
Hide resolved
...rino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/group/CachingGroupProvider.java
Outdated
Show resolved
Hide resolved
...rino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/group/LoadingGroupProvider.java
Outdated
Show resolved
Hide resolved
...-plugin-toolkit/src/test/java/io/trino/plugin/base/cache/group/TestCachingGroupProvider.java
Outdated
Show resolved
Hide resolved
...n/trino-ldap-group-provider/src/main/java/io/trino/plugin/ldapgroup/LdapHighLevelClient.java
Outdated
Show resolved
Hide resolved
...n/trino-ldap-group-provider/src/main/java/io/trino/plugin/ldapgroup/LdapHighLevelClient.java
Outdated
Show resolved
Hide resolved
...n/trino-ldap-group-provider/src/main/java/io/trino/plugin/ldapgroup/LdapHighLevelClient.java
Outdated
Show resolved
Hide resolved
...trino-ldap-group-provider/src/test/java/io/trino/plugin/ldapgroup/TestLdapGroupProvider.java
Outdated
Show resolved
Hide resolved
...group-provider/src/test/java/io/trino/plugin/ldapgroup/TestLdapGroupProviderIntegration.java
Outdated
Show resolved
Hide resolved
This would be great to have. Any ETA of this? |
If it helps with reviewing or selling the idea we can cherry-pick your commit into this PR so its all in one place. |
Please cherry-pick. This is good idea. |
abd6fcd
to
7f0a86e
Compare
Addressed all the review comments and moved some of the components around. Two big changes:
The choice between the two mechanisms is done by setting the Requested by @Praveen2112 I moved the |
7f0a86e
to
b518742
Compare
@Praveen2112 Please take a look when you have time. The failing test is part of the Hive suite, I assume its being flaky. |
This pull request has gone a while without any activity. Tagging the Trino developer relations team: @bitsondatadev @colebow @mosabua |
I'll taking a look this week. Sorry for the delay |
One minor nit : I have is can we add the caching logic as a final commit, once the base LDAP implementation has been added ? |
I would like to have a discussion on
Ideally Group is an LDAP object while these users attributes are a part of the LDAP object. This group can be used for any access controls does it makes sense to rely on a non LDAP object here ? WDYT ? |
Let me know if you want to catch up offline about this, I'm on the Trino slack. Keep in mind this is configurable. By default no user attributes are mapped to groups. The plugin needs to be configured with what attributes to map. See the tests for examples. I don't see what the issue is. To Trino (and to most systems for that matter) grops are just strings; groups gain meaning when access control policies are bound to them. Downstream from the group provider it is irelevant where the groups came from. We already use this at Bloomberg as part of our access control systems so we can create policies more nuanced than "is user x part of group y" |
This pull request has gone a while without any activity. Tagging the Trino developer relations team: @bitsondatadev @colebow @mosabua |
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.
I'm a bit confused on different mechanism being used for user attributes for ldap.user-search-attributes
we use it key and value while for others it is just value
- Can it be symmetric ?
{ | ||
private static final Logger log = Logger.get(LdapGroupProvider.class); | ||
|
||
private final String userMemberOfAttribute; |
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.
Instead of referring userMemberOfAttribute
, can we use LdapGroupProviderConfig#getLdapUserSearchAttributes` ?
plugin/trino-ldap-group-provider/src/main/java/io/trino/plugin/ldapgroup/LdapGroupProvider.java
Outdated
Show resolved
Hide resolved
log.warn("Group with DN [%s] has no Relative Domain Names. Ignoring group.", groupDN); | ||
return Optional.empty(); | ||
} | ||
Rdn lastRDN = groupRDNs.getLast(); |
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.
For my understanding - Why specifically the last entry ?
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.
an LDAP Distinguished Name (DN) is a chain of multiple Relative Distinguished Names (RDNs). for example in cn=users,ou=groups,dc=trino,dc=io
- cn=users
and ou=groups
are RDNs.
these are meant to be read from right to left (you can notice they get more specific). getRdns()
will return them in this order, so the last element is the least specific RDN, usually what we would call the "name". in the example above it would be cn=users
.
parsing group names from DNs is an heuristic based on the assumption that the last RDN is the Canonical Name we are looking for.
|
||
private LdapGroupProviderConfig config; | ||
private LdapGroupProviderFilteringClientConfig filteringConfig; | ||
private TestingLdapClient mockClient; |
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.
nit: ldapClient
public final class TestingNamingEnumeration<T> | ||
implements NamingEnumeration<T> | ||
{ | ||
private final Iterator<T> iter; |
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.
nit: Can we avoid using abbreviation ?
public TestLdapGroupProviderIntegration() | ||
throws Exception | ||
{ | ||
closer = Closer.create(); |
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.
Can we move them to a setup
method and use @BeforeAll
instead of constructor
@ParameterizedTest | ||
@MethodSource("provideUsersAndExpectedGroups") | ||
public void testGetGroups(ConfigBuilder configBuilder, String userName, Set<String> expectedGroups) |
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.
It is not generally recommended to use ParameterizedTest
- In general, they make it harder to debug tests - We could try to create some sort of an assertYYY
- For reference we could try something like TestDecimalCoercers
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.
will look into this a bit, but I personally don't see an overall ban on ParametrizedTests
as a good thing. they may be overused but they do have a place
@Praveen2112 in reply to your review comment and #20157 (comment)_ No, it cannot be symmetric. We prefix attributes from We covered this topic at length in our slack chat, please refer to that |
This pull request has gone a while without any activity. Tagging the Trino developer relations team: @bitsondatadev @colebow @mosabua |
Will this pull request be added soon? I think there are a lot of people looking forward to it. |
I would like to get a consensus on cc: @Praveen2112 @dain |
I would like to get @dain's opinion here - on handling arbitrary user attributes. |
I don't think we should the feature to map ldap attributes to groups. Instead we should work on adding data from authentication to the session, and functions to access this data (so it can be used in ABAC expressions). I'm not sure how we want to do this, but I'd start with a survey of how others have done this. If there is a consensus from others, the design is simple. This would be a separate project from this PR. |
Thanks for the input Dain. I agree we should have a better system for fetching and passing around user attributes (attributes = key-value string pairs), but I don't think it should be bound to the login process. It could it be its own separate plugin type ( For example, in my use-case, Trino is setup with both oauth and LDAP user/password authentication, but the user attributes I care about are only in LDAP. I'm not seeing much support for the attribute to group mapping in this PR; that's ok, I will have to remove it. It may take a bit since this isn't a very high priority item for me currently. |
Thanks for the answer. Of course, we need to choose a more suitable solution. The main thing is that you can manage access rights using ldap groups right away without additional plugins. We tried the ldap group provider implementation, which is freely available. This is a good solution that is convenient to use. |
This Guice Module can be used to enable caching in the group provider, by adding it to the list of modules in a Guice context in a group provider factory, or to any other Guice context as needed. Features: * Configurable configuration prefix * Ability to bind the final `GroupProvider` with a custom binding annotation * useful especially when the Guice context is not entirely isolated and there are other `GroupProvider` bindings in it * An `@Inject`-able hook for cache invalidation Author: Krzysztof Sobolewski <[email protected]> Date: Tue Jul 11 16:48:28 2023 +0200
ea20a24
to
dc998eb
Compare
dc998eb
to
154f761
Compare
Is there any progress on this? I've been looking for a working group ldap plugin, and seeing years of endless arguing over non-core enhancements is somewhat frustrating. I'm willing to help if I can, just to get this moving along. |
We had chat about this PR during the last Trino contributor call https://github.com/trinodb/trino/wiki/Contributor-meetings#trino-contributor-call-24-oct-2024. I don't have a lot of time to work on this unfortunately. We are looking for someone to take the PR to competition, its fairly close. The discussion on the last few comments between me and Dain was about handling custom user attributes in LDAP. The decision was for that functionality to be removed. In my last push I stripped all of that out. The code for fetching groups from LDAP is in place. The next steps are:
@OmerRaifler (I hope that is the right github user, slack user is https://trinodb.slack.com/team/U06BF92CABC) was interested in working on this, but I haven't heard anything from them @ilsaloving Please feel free to jump in |
This PR has now moved to #23900 as @OmerRaifler is taking ownership. We hope to get this shipped soon! |
Description
Adds an implementation of the Groups Provider plugin type that loads user groups from LDAP.
Supports filtering of fetched groups at the LDAP query level.
Supports fetching of extra users attributes, which are mapped to groups with the pattern
{attribute}={value}
.The plugin uses a 2-pass approach:
Result are cached with a configurable TTL. The cache has extra logic to save loaded groups only when both steps complete successfully, otherwise returning either empty groups of results from step 1.
Additional context and related issues
Sample configuration:
The PR also updates the Trino LDAP toolkit to support pass-through search filter arguments to the LDAP client. This lets the LDAP server handle argument substitutions.
Release notes
( ) This is not user-visible or is docs only, and no release notes are required.
(x) Release notes are required. Please propose a release note for me.
( ) Release notes are required, with the following suggested text: