blob: 9a6e623bc6eb8710dcb6609b6e0a5e43aff89e57 [file] [log] [blame]
/*
* 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.sentry.binding.solr.authz;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Set;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.sentry.binding.solr.conf.SolrAuthzConf;
import org.apache.sentry.binding.solr.conf.SolrAuthzConf.AuthzConfVars;
import org.apache.sentry.core.common.ActiveRoleSet;
import org.apache.sentry.core.common.Subject;
import org.apache.sentry.core.model.search.Collection;
import org.apache.sentry.core.model.search.SearchModelAction;
import org.apache.sentry.policy.common.PolicyEngine;
import org.apache.sentry.provider.common.AuthorizationProvider;
import org.apache.sentry.provider.common.GroupMappingService;
import org.apache.sentry.provider.common.ProviderBackend;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
public class SolrAuthzBinding {
private static final Logger LOG = LoggerFactory
.getLogger(SolrAuthzBinding.class);
private static final String[] HADOOP_CONF_FILES = {"core-site.xml",
"hdfs-site.xml", "mapred-site.xml", "yarn-site.xml", "hadoop-site.xml"};
public static final String KERBEROS_ENABLED = "solr.hdfs.security.kerberos.enabled";
public static final String KERBEROS_KEYTAB = "solr.hdfs.security.kerberos.keytabfile";
public static final String KERBEROS_PRINCIPAL = "solr.hdfs.security.kerberos.principal";
private static final String kerberosEnabledProp = Strings.nullToEmpty(System.getProperty(KERBEROS_ENABLED)).trim();
private static final String keytabProp = Strings.nullToEmpty(System.getProperty(KERBEROS_KEYTAB)).trim();
private static final String principalProp = Strings.nullToEmpty(System.getProperty(KERBEROS_PRINCIPAL)).trim();
private static Boolean kerberosInit;
private final SolrAuthzConf authzConf;
private final AuthorizationProvider authProvider;
private final GroupMappingService groupMapping;
public SolrAuthzBinding (SolrAuthzConf authzConf) throws Exception {
this.authzConf = authzConf;
this.authProvider = getAuthProvider();
this.groupMapping = authProvider.getGroupMapping();
}
// Instantiate the configured authz provider
private AuthorizationProvider getAuthProvider() throws Exception {
// get the provider class and resources from the authz config
String authProviderName = authzConf.get(AuthzConfVars.AUTHZ_PROVIDER.getVar());
String resourceName =
authzConf.get(AuthzConfVars.AUTHZ_PROVIDER_RESOURCE.getVar());
String providerBackendName =
authzConf.get(AuthzConfVars.AUTHZ_PROVIDER_BACKEND.getVar());
String policyEngineName =
authzConf.get(AuthzConfVars.AUTHZ_POLICY_ENGINE.getVar());
LOG.debug("Using authorization provider " + authProviderName +
" with resource " + resourceName + ", policy engine "
+ policyEngineName + ", provider backend " + providerBackendName);
// load the provider backend class
Constructor<?> providerBackendConstructor =
Class.forName(providerBackendName).getDeclaredConstructor(Configuration.class, String.class);
providerBackendConstructor.setAccessible(true);
if (kerberosEnabledProp.equalsIgnoreCase("true")) {
initKerberos(keytabProp, principalProp);
}
Configuration conf = getConf();
ProviderBackend providerBackend =
(ProviderBackend) providerBackendConstructor.newInstance(new Object[] {conf, resourceName});
// load the policy engine class
Constructor<?> policyConstructor =
Class.forName(policyEngineName).getDeclaredConstructor(ProviderBackend.class);
policyConstructor.setAccessible(true);
PolicyEngine policyEngine =
(PolicyEngine) policyConstructor.newInstance(new Object[] {providerBackend});
// load the authz provider class
Constructor<?> constrctor =
Class.forName(authProviderName).getDeclaredConstructor(String.class, PolicyEngine.class);
constrctor.setAccessible(true);
return (AuthorizationProvider) constrctor.newInstance(new Object[] {resourceName, policyEngine});
}
/**
* Authorize access to an index/collection
* @param subject
* @param collection
* @param actions
* @throws SentrySolrAuthorizationException
*/
public void authorizeCollection(Subject subject, Collection collection, Set<SearchModelAction> actions) throws SentrySolrAuthorizationException {
boolean isDebug = LOG.isDebugEnabled();
if(isDebug) {
LOG.debug("Going to authorize collection " + collection.getName() +
" for subject " + subject.getName());
LOG.debug("Actions: " + actions);
}
if (!authProvider.hasAccess(subject, Arrays.asList(new Collection[] {collection}), actions,
ActiveRoleSet.ALL)) {
throw new SentrySolrAuthorizationException("User " + subject.getName() +
" does not have privileges for " + collection.getName());
}
}
/**
* Get the list of groups the user belongs to
* @param user
* @return list of groups the user belongs to
*/
public Set<String> getGroups(String user) {
return groupMapping.getGroups(user);
}
private Configuration getConf() throws IOException {
Configuration conf = new Configuration();
String confDir = System.getProperty("solr.hdfs.confdir");
if (confDir != null && confDir.length() > 0) {
File confDirFile = new File(confDir);
if (!confDirFile.exists()) {
throw new IOException("Resource directory does not exist: " + confDirFile.getAbsolutePath());
}
if (!confDirFile.isDirectory()) {
throw new IOException("Specified resource directory is not a directory" + confDirFile.getAbsolutePath());
}
if (!confDirFile.canRead()) {
throw new IOException("Resource directory must be readable by the Solr process: " + confDirFile.getAbsolutePath());
}
for (String file : HADOOP_CONF_FILES) {
if (new File(confDirFile, file).exists()) {
conf.addResource(new Path(confDir, file));
}
}
}
return conf;
}
/**
* Initialize kerberos via UserGroupInformation. Will only attempt to login
* during the first request, subsequent calls will have no effect.
*/
public static void initKerberos(String keytabFile, String principal) {
if (keytabFile == null || keytabFile.length() == 0) {
throw new IllegalArgumentException("keytabFile required because kerberos is enabled");
}
if (principal == null || principal.length() == 0) {
throw new IllegalArgumentException("principal required because kerberos is enabled");
}
synchronized (SolrAuthzBinding.class) {
if (kerberosInit == null) {
kerberosInit = new Boolean(true);
Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "kerberos");
UserGroupInformation.setConfiguration(conf);
LOG.info(
"Attempting to acquire kerberos ticket with keytab: {}, principal: {} ",
keytabFile, principal);
try {
UserGroupInformation.loginUserFromKeytab(principal, keytabFile);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
LOG.info("Got Kerberos ticket");
}
}
}
}