Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/trino-plugin-toolkit/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@
<artifactId>joda-time</artifactId>
</dependency>

<dependency>
<groupId>org.gaul</groupId>
<artifactId>modernizer-maven-annotations</artifactId>
</dependency>

<dependency>
<groupId>org.weakref</groupId>
<artifactId>jmxutils</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.plugin.password.jndi;
package io.trino.plugin.base.jndi;

import org.gaul.modernizer_maven_annotations.SuppressModernizer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.plugin.password.ldap;
package io.trino.plugin.base.ldap;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import io.airlift.log.Logger;
import io.airlift.units.Duration;
import io.trino.plugin.base.ssl.SslUtils;
Expand All @@ -34,9 +33,8 @@
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static io.trino.plugin.password.jndi.JndiUtils.createDirContext;
import static io.trino.plugin.base.jndi.JndiUtils.createDirContext;
import static java.util.Objects.requireNonNull;
import static javax.naming.Context.INITIAL_CONTEXT_FACTORY;
import static javax.naming.Context.PROVIDER_URL;
Expand All @@ -45,16 +43,16 @@
import static javax.naming.Context.SECURITY_CREDENTIALS;
import static javax.naming.Context.SECURITY_PRINCIPAL;

public class JdkLdapAuthenticatorClient
implements LdapAuthenticatorClient
public class JdkLdapClient
implements LdapClient
{
private static final Logger log = Logger.get(JdkLdapAuthenticatorClient.class);
private static final Logger log = Logger.get(JdkLdapClient.class);

private final Map<String, String> basicEnvironment;
private final Optional<SSLContext> sslContext;

@Inject
public JdkLdapAuthenticatorClient(LdapConfig ldapConfig)
public JdkLdapClient(LdapClientConfig ldapConfig)
{
String ldapUrl = requireNonNull(ldapConfig.getLdapUrl(), "ldapUrl is null");
if (ldapUrl.startsWith("ldap://")) {
Expand Down Expand Up @@ -87,42 +85,22 @@ public JdkLdapAuthenticatorClient(LdapConfig ldapConfig)
}

@Override
public void validatePassword(String userDistinguishedName, String password)
public <T> T executeLdapQuery(String userName, String password, LdapQuery ldapQuery, LdapSearchResultProcessor<T> resultProcessor)
throws NamingException
{
createUserDirContext(userDistinguishedName, password).close();
}

@Override
public boolean isGroupMember(String searchBase, String groupSearch, String contextUserDistinguishedName, String contextPassword)
throws NamingException
{
try (CloseableContext context = createUserDirContext(contextUserDistinguishedName, contextPassword);
CloseableSearchResults search = searchContext(searchBase, groupSearch, context)) {
return search.hasMore();
try (CloseableContext context = createUserDirContext(userName, password);
CloseableSearchResults search = searchContext(ldapQuery, context)) {
return resultProcessor.process(search.searchResults);
}
}

@Override
public Set<String> lookupUserDistinguishedNames(String searchBase, String searchFilter, String contextUserDistinguishedName, String contextPassword)
throws NamingException
{
try (CloseableContext context = createUserDirContext(contextUserDistinguishedName, contextPassword);
CloseableSearchResults search = searchContext(searchBase, searchFilter, context)) {
ImmutableSet.Builder<String> distinguishedNames = ImmutableSet.builder();
while (search.hasMore()) {
distinguishedNames.add(search.next().getNameInNamespace());
}
return distinguishedNames.build();
}
}

private static CloseableSearchResults searchContext(String searchBase, String searchFilter, CloseableContext context)
private static CloseableSearchResults searchContext(LdapQuery ldapQuery, CloseableContext context)
throws NamingException
{
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
return new CloseableSearchResults(context.search(searchBase, searchFilter, searchControls));
searchControls.setReturningAttributes(ldapQuery.getAttributes());
return new CloseableSearchResults(context.search(ldapQuery.getSearchBase(), ldapQuery.getSearchFilter(), searchControls));
}

private CloseableContext createUserDirContext(String userDistinguishedName, String password)
Expand Down Expand Up @@ -211,16 +189,10 @@ public CloseableSearchResults(NamingEnumeration<SearchResult> searchResults)
this.searchResults = requireNonNull(searchResults, "searchResults is null");
}

public SearchResult next()
throws NamingException
{
return searchResults.next();
}

public boolean hasMore()
public NamingEnumeration<SearchResult> getSearchResult()
throws NamingException
{
return searchResults.hasMore();
return searchResults;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.plugin.base.ldap;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchResult;

public interface LdapClient
{
<T> T executeLdapQuery(String userName, String password, LdapQuery ldapQuery, LdapSearchResultProcessor<T> resultProcessor)
throws NamingException;

interface LdapSearchResultProcessor<T>
{
T process(NamingEnumeration<SearchResult> searchResults)
throws NamingException;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.plugin.password.ldap;
package io.trino.plugin.base.ldap;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import io.airlift.configuration.Config;
import io.airlift.configuration.ConfigDescription;
import io.airlift.configuration.ConfigSecuritySensitive;
Expand All @@ -27,29 +25,20 @@
import javax.validation.constraints.Pattern;

import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static com.google.common.base.Strings.nullToEmpty;
import static java.util.Objects.requireNonNull;

@DefunctConfig("ldap.ssl-trust-certificate")
public class LdapConfig
public class LdapClientConfig
{
private String ldapUrl;
private boolean allowInsecure;
private File keystorePath;
private String keystorePassword;
private File trustStorePath;
private String truststorePassword;
private List<String> userBindSearchPatterns = ImmutableList.of();
private String groupAuthorizationSearchPattern;
private String userBaseDistinguishedName;
private String bindDistinguishedName;
private String bindPassword;
private boolean ignoreReferrals;
private Duration ldapCacheTtl = new Duration(1, TimeUnit.HOURS);
private Optional<Duration> ldapConnectionTimeout = Optional.empty();
private Optional<Duration> ldapReadTimeout = Optional.empty();

Expand All @@ -62,7 +51,7 @@ public String getLdapUrl()

@Config("ldap.url")
@ConfigDescription("URL of the LDAP server")
public LdapConfig setLdapUrl(String url)
public LdapClientConfig setLdapUrl(String url)
{
this.ldapUrl = url;
return this;
Expand All @@ -75,7 +64,7 @@ public boolean isAllowInsecure()

@Config("ldap.allow-insecure")
@ConfigDescription("Allow insecure connection to the LDAP server")
public LdapConfig setAllowInsecure(boolean allowInsecure)
public LdapClientConfig setAllowInsecure(boolean allowInsecure)
{
this.allowInsecure = allowInsecure;
return this;
Expand All @@ -94,7 +83,7 @@ public boolean isUrlConfigurationValid()

@Config("ldap.ssl.keystore.path")
@ConfigDescription("Path to the PEM or JKS key store")
public LdapConfig setKeystorePath(File path)
public LdapClientConfig setKeystorePath(File path)
{
this.keystorePath = path;
return this;
Expand All @@ -108,7 +97,7 @@ public Optional<String> getKeystorePassword()
@Config("ldap.ssl.keystore.password")
@ConfigSecuritySensitive
@ConfigDescription("Password for the key store")
public LdapConfig setKeystorePassword(String password)
public LdapClientConfig setKeystorePassword(String password)
{
this.keystorePassword = password;
return this;
Expand All @@ -121,7 +110,7 @@ public LdapConfig setKeystorePassword(String password)

@Config("ldap.ssl.truststore.path")
@ConfigDescription("Path to the PEM or JKS trust store")
public LdapConfig setTrustStorePath(File path)
public LdapClientConfig setTrustStorePath(File path)
{
this.trustStorePath = path;
return this;
Expand All @@ -135,122 +124,33 @@ public Optional<String> getTruststorePassword()
@Config("ldap.ssl.truststore.password")
@ConfigSecuritySensitive
@ConfigDescription("Password for the trust store")
public LdapConfig setTruststorePassword(String password)
public LdapClientConfig setTruststorePassword(String password)
{
this.truststorePassword = password;
return this;
}

@NotNull
public List<String> getUserBindSearchPatterns()
{
return userBindSearchPatterns;
}

public LdapConfig setUserBindSearchPatterns(List<String> userBindSearchPatterns)
{
this.userBindSearchPatterns = requireNonNull(userBindSearchPatterns, "userBindSearchPatterns is null");
return this;
}

@Config("ldap.user-bind-pattern")
@ConfigDescription("Custom user bind pattern. Example: ${USER}@example.com")
public LdapConfig setUserBindSearchPatterns(String userBindSearchPatterns)
{
this.userBindSearchPatterns = Splitter.on(":")
.trimResults()
.omitEmptyStrings()
.splitToList(userBindSearchPatterns);
return this;
}

public String getGroupAuthorizationSearchPattern()
{
return groupAuthorizationSearchPattern;
}

@Config("ldap.group-auth-pattern")
@ConfigDescription("Custom group authorization check query. Example: &(objectClass=user)(memberOf=cn=group)(user=username)")
public LdapConfig setGroupAuthorizationSearchPattern(String groupAuthorizationSearchPattern)
{
this.groupAuthorizationSearchPattern = groupAuthorizationSearchPattern;
return this;
}

public String getUserBaseDistinguishedName()
{
return userBaseDistinguishedName;
}

@Config("ldap.user-base-dn")
@ConfigDescription("Base distinguished name of the user. Example: dc=example,dc=com")
public LdapConfig setUserBaseDistinguishedName(String userBaseDistinguishedName)
{
this.userBaseDistinguishedName = userBaseDistinguishedName;
return this;
}

public String getBindDistingushedName()
{
return bindDistinguishedName;
}

@Config("ldap.bind-dn")
@ConfigDescription("Bind distinguished name. Example: CN=User Name,OU=CITY_OU,OU=STATE_OU,DC=domain,DC=domain_root")
public LdapConfig setBindDistingushedName(String bindDistingushedName)
{
this.bindDistinguishedName = bindDistingushedName;
return this;
}

public String getBindPassword()
{
return bindPassword;
}

@Config("ldap.bind-password")
@ConfigDescription("Bind password used. Example: password1234")
@ConfigSecuritySensitive
public LdapConfig setBindPassword(String bindPassword)
{
this.bindPassword = bindPassword;
return this;
}

public boolean isIgnoreReferrals()
{
return ignoreReferrals;
}

@Config("ldap.ignore-referrals")
@ConfigDescription("Referrals allow finding entries across multiple LDAP servers. Ignore them to only search within 1 LDAP server")
public LdapConfig setIgnoreReferrals(boolean ignoreReferrals)
public LdapClientConfig setIgnoreReferrals(boolean ignoreReferrals)
{
this.ignoreReferrals = ignoreReferrals;
return this;
}

@NotNull
public Duration getLdapCacheTtl()
{
return ldapCacheTtl;
}

@Config("ldap.cache-ttl")
public LdapConfig setLdapCacheTtl(Duration ldapCacheTtl)
{
this.ldapCacheTtl = ldapCacheTtl;
return this;
}

public Optional<Duration> getLdapConnectionTimeout()
{
return ldapConnectionTimeout;
}

@Config("ldap.timeout.connect")
@ConfigDescription("Timeout for establishing a connection")
public LdapConfig setLdapConnectionTimeout(Duration ldapConnectionTimeout)
public LdapClientConfig setLdapConnectionTimeout(Duration ldapConnectionTimeout)
{
this.ldapConnectionTimeout = Optional.ofNullable(ldapConnectionTimeout);
return this;
Expand All @@ -263,7 +163,7 @@ public Optional<Duration> getLdapReadTimeout()

@Config("ldap.timeout.read")
@ConfigDescription("Timeout for reading data from LDAP")
public LdapConfig setLdapReadTimeout(Duration ldapReadTimeout)
public LdapClientConfig setLdapReadTimeout(Duration ldapReadTimeout)
{
this.ldapReadTimeout = Optional.ofNullable(ldapReadTimeout);
return this;
Expand Down
Loading