org.apache.hive.service.auth.ldap.LdapSearch Maven / Gradle / Ivy
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.hive.service.auth.ldap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchResult;
import org.apache.hadoop.hive.conf.HiveConf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implements search for LDAP.
*/
public final class LdapSearch implements DirSearch {
private static final Logger LOG = LoggerFactory.getLogger(LdapSearch.class);
private final String baseDn;
private final List groupBases;
private final List userBases;
private final List userPatterns;
private final QueryFactory queries;
private final DirContext ctx;
/**
* Construct an instance of {@code LdapSearch}.
* @param conf Hive configuration
* @param ctx Directory service that will be used for the queries.
* @throws NamingException
*/
public LdapSearch(HiveConf conf, DirContext ctx) throws NamingException {
baseDn = conf.getVar(HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_BASEDN);
userPatterns = LdapUtils.parseDnPatterns(conf,
HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_USERDNPATTERN);
groupBases = LdapUtils.patternsToBaseDns(LdapUtils.parseDnPatterns(conf,
HiveConf.ConfVars.HIVE_SERVER2_PLAIN_LDAP_GROUPDNPATTERN));
userBases = LdapUtils.patternsToBaseDns(userPatterns);
this.ctx = ctx;
queries = new QueryFactory(conf);
}
/**
* Closes this search object and releases any system resources associated
* with it. If the search object is already closed then invoking this
* method has no effect.
*/
@Override
public void close() {
try {
ctx.close();
} catch (NamingException e) {
LOG.warn("Exception when closing LDAP context:", e);
}
}
/**
* {@inheritDoc}
*/
@Override
public String findUserDn(String user) throws NamingException {
List allLdapNames;
if (LdapUtils.isDn(user)) {
String userBaseDn = LdapUtils.extractBaseDn(user);
String userRdn = LdapUtils.extractFirstRdn(user);
allLdapNames = execute(Collections.singletonList(userBaseDn),
queries.findUserDnByRdn(userRdn)).getAllLdapNames();
} else {
allLdapNames = findDnByPattern(userPatterns, user);
if (allLdapNames.isEmpty()) {
allLdapNames = execute(userBases, queries.findUserDnByName(user)).getAllLdapNames();
}
}
if (allLdapNames.size() == 1) {
return allLdapNames.get(0);
} else {
LOG.info("Expected exactly one user result for the user: {}, but got {}. Returning null",
user, allLdapNames.size());
LOG.debug("Matched users: {}", allLdapNames);
return null;
}
}
private List findDnByPattern(List patterns, String name) throws NamingException {
for (String pattern : patterns) {
String baseDnFromPattern = LdapUtils.extractBaseDn(pattern);
String rdn = LdapUtils.extractFirstRdn(pattern).replaceAll("%s", name);
List list = execute(Collections.singletonList(baseDnFromPattern),
queries.findDnByPattern(rdn)).getAllLdapNames();
if (!list.isEmpty()) {
return list;
}
}
return Collections.emptyList();
}
/**
* {@inheritDoc}
*/
@Override
public List findGroupsForUser(String userDn) throws NamingException {
String userName = LdapUtils.extractUserName(userDn);
return execute(groupBases, queries.findGroupsForUser(userName, userDn)).getAllLdapNames();
}
/**
* {@inheritDoc}
*/
@Override
public List executeCustomQuery(String query) throws NamingException {
return execute(Collections.singletonList(baseDn), queries.customQuery(query))
.getAllLdapNamesAndAttributes();
}
private SearchResultHandler execute(Collection baseDns, Query query) {
List> searchResults = new ArrayList<>();
LOG.debug("Executing a query: '{}' with base DNs {}.", query.getFilter(), baseDns);
for (String aBaseDn : baseDns) {
try {
NamingEnumeration searchResult = ctx.search(aBaseDn, query.getFilter(),
query.getControls());
if (searchResult != null) {
searchResults.add(searchResult);
}
} catch (NamingException ex) {
LOG.debug("Exception happened for query '" + query.getFilter() +
"' with base DN '" + aBaseDn + "'", ex);
}
}
return new SearchResultHandler(searchResults);
}
}