You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by co...@apache.org on 2017/11/16 09:57:04 UTC

[27/32] sentry git commit: SENTRY-1475: Integrate Sentry with Solr 7 authorization framework. (Hrishikesh Gadre, reviewed by Kalyan Kumar Kalvagadda)

SENTRY-1475: Integrate Sentry with Solr 7 authorization framework. (Hrishikesh Gadre, reviewed by Kalyan Kumar Kalvagadda)


Project: http://git-wip-us.apache.org/repos/asf/sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/e62fa28d
Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/e62fa28d
Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/e62fa28d

Branch: refs/heads/akolb-cli
Commit: e62fa28d0fe342a8a154e0f50221cf34a658a045
Parents: 8a80d60
Author: Kalyan Kumar Kalvagadda <kk...@cloudera.com>
Authored: Mon Nov 13 08:37:22 2017 -0600
Committer: Kalyan Kumar Kalvagadda <kk...@cloudera.com>
Committed: Mon Nov 13 08:37:22 2017 -0600

----------------------------------------------------------------------
 pom.xml                                         |  12 +-
 sentry-binding/sentry-binding-solr/pom.xml      |  11 +-
 .../authz/SentrySolrAuthorizationException.java |  25 -
 .../solr/authz/SentrySolrPluginImpl.java        | 408 ++++++++
 .../binding/solr/authz/SolrAuthzBinding.java    | 268 ++----
 .../binding/solr/authz/SolrAuthzUtil.java       | 271 ++++++
 .../sentry/binding/solr/conf/SolrAuthzConf.java |  14 +-
 .../org/apache/solr/sentry/AuditLogger.java     |  92 ++
 .../RollingFileWithoutDeleteAppender.java       | 182 ++++
 .../sentry/binding/solr/HdfsTestUtil.java       |  50 +-
 .../binding/solr/TestSolrAuthzBinding.java      | 338 ++++---
 .../solr/AbstractTestSearchPolicyEngine.java    | 129 ---
 .../solr/AbstractTestSolrPolicyEngine.java      | 129 +++
 .../policy/solr/SearchPolicyTestUtil.java       |  45 -
 .../sentry/policy/solr/SolrPolicyTestUtil.java  |  45 +
 .../solr/TestCollectionRequiredInRole.java      |  64 --
 ...SearchAuthorizationProviderGeneralCases.java | 193 ----
 ...SearchAuthorizationProviderSpecialCases.java |  84 --
 .../solr/TestSearchModelAuthorizables.java      |  54 --
 .../policy/solr/TestSearchPolicyEngineDFS.java  |  74 --
 .../solr/TestSearchPolicyEngineLocalFS.java     |  43 -
 .../policy/solr/TestSearchPolicyNegative.java   | 101 --
 ...stSolrAuthorizationProviderGeneralCases.java | 196 ++++
 ...stSolrAuthorizationProviderSpecialCases.java |  84 ++
 .../policy/solr/TestSolrModelAuthorizables.java |  54 ++
 .../policy/solr/TestSolrPolicyEngineDFS.java    |  74 ++
 .../solr/TestSolrPolicyEngineLocalFS.java       |  43 +
 .../policy/solr/TestSolrPolicyNegative.java     | 101 ++
 .../solr/TestCommonPrivilegeForSearch.java      | 221 -----
 .../solr/TestCommonPrivilegeForSolr.java        | 293 ++++++
 .../src/test/resources/test-authz-provider.ini  |   4 +-
 sentry-core/pom.xml                             |   2 +-
 sentry-core/sentry-core-model-search/pom.xml    |  43 -
 .../sentry/core/model/search/Collection.java    |  51 -
 .../apache/sentry/core/model/search/Field.java  |  54 --
 .../core/model/search/SearchActionFactory.java  |  80 --
 .../core/model/search/SearchConstants.java      |  35 -
 .../core/model/search/SearchModelAction.java    |  39 -
 .../model/search/SearchModelAuthorizable.java   |  29 -
 .../model/search/SearchModelAuthorizables.java  |  50 -
 .../core/model/search/SearchPrivilegeModel.java |  60 --
 .../AbstractSearchPrivilegeValidator.java       |  52 --
 .../CollectionRequiredInPrivilege.java          |  43 -
 .../sentry/core/search/TestCollection.java      |  50 -
 .../core/search/TestSearchBitFieldAction.java   |  73 --
 sentry-core/sentry-core-model-solr/pom.xml      |  43 +
 .../sentry/core/model/solr/AdminOperation.java  |  42 +
 .../sentry/core/model/solr/Collection.java      |  29 +
 .../apache/sentry/core/model/solr/Config.java   |  27 +
 .../apache/sentry/core/model/solr/Field.java    |  30 +
 .../apache/sentry/core/model/solr/Schema.java   |  27 +
 .../core/model/solr/SolrActionFactory.java      |  80 ++
 .../sentry/core/model/solr/SolrConstants.java   |  39 +
 .../sentry/core/model/solr/SolrModelAction.java |  39 +
 .../core/model/solr/SolrModelAuthorizable.java  |  60 ++
 .../core/model/solr/SolrModelAuthorizables.java |  58 ++
 .../core/model/solr/SolrPrivilegeModel.java     |  66 ++
 .../solr/validator/SolrPrivilegeValidator.java  | 101 ++
 .../apache/sentry/core/solr/TestCollection.java |  49 +
 .../core/solr/TestSolrBitFieldAction.java       |  73 ++
 sentry-dist/pom.xml                             |  14 +-
 sentry-provider/sentry-provider-db/pom.xml      |  15 +-
 .../persistent/PrivilegeOperatePersistence.java |   4 +-
 .../tools/GenericPrivilegeConverter.java        |   8 +-
 .../db/generic/tools/SentryConfigToolSolr.java  |   4 +-
 .../TestPrivilegeOperatePersistence.java        | 108 +--
 .../persistent/TestSentryGMPrivilege.java       |  54 +-
 .../service/persistent/TestSentryRole.java      |   2 +-
 .../TestSentryGenericPolicyProcessor.java       |  14 +-
 .../TestSentryGenericServiceIntegration.java    |  36 +-
 .../generic/tools/TestSentryConfigToolSolr.java |   2 +-
 .../db/generic/tools/TestSentryShellSolr.java   |   2 +-
 sentry-solr/pom.xml                             |   1 -
 sentry-solr/solr-sentry-core/pom.xml            |  58 --
 .../org/apache/solr/sentry/AuditLogger.java     |  97 --
 .../RollingFileWithoutDeleteAppender.java       | 175 ----
 .../solr/sentry/SecureRequestHandlerUtil.java   |  83 --
 .../SentryIndexAuthorizationSingleton.java      | 255 -----
 sentry-solr/solr-sentry-handlers/pom.xml        |  10 +-
 .../SecureDocumentAnalysisRequestHandler.java   |  33 -
 .../SecureFieldAnalysisRequestHandler.java      |  33 -
 .../solr/handler/SecureRealTimeGetHandler.java  |  36 -
 .../solr/handler/SecureReplicationHandler.java  |  38 -
 .../solr/handler/admin/SecureAdminHandlers.java | 183 ----
 .../handler/admin/SecureCollectionsHandler.java |  89 --
 .../handler/admin/SecureCoreAdminHandler.java   | 181 ----
 .../solr/handler/admin/SecureInfoHandler.java   |  36 -
 .../QueryDocAuthorizationComponent.java         | 116 ++-
 .../QueryIndexAuthorizationComponent.java       |  79 --
 .../component/SecureRealTimeGetComponent.java   | 356 -------
 .../UpdateIndexAuthorizationProcessor.java      | 103 ---
 ...pdateIndexAuthorizationProcessorFactory.java |  41 -
 .../lib/classes/empty-file-main-lib.txt         |   1 -
 .../handler/TestSecureAnalysisHandlers.java     |  82 --
 .../handler/TestSecureReplicationHandler.java   |  63 --
 .../handler/admin/SecureAdminHandlersTest.java  | 176 ----
 .../admin/SecureCollectionsHandlerTest.java     |  84 --
 .../admin/SecureCoreAdminHandlerTest.java       | 209 -----
 .../handler/admin/SecureInfoHandlerTest.java    | 101 --
 .../QueryDocAuthorizationComponentTest.java     | 265 ------
 .../QueryIndexAuthorizationComponentTest.java   | 127 ---
 .../SentryIndexAuthorizationSingletonTest.java  | 256 -----
 .../sentry/SentrySingletonTestInstance.java     |  93 --
 .../org/apache/solr/sentry/SentryTestBase.java  | 187 ----
 .../UpdateIndexAuthorizationProcessorTest.java  | 193 ----
 sentry-tests/sentry-tests-solr/pom.xml          | 211 ++++-
 .../e2e/solr/AbstractSolrSentryTestBase.java    | 923 -------------------
 .../e2e/solr/AbstractSolrSentryTestCase.java    | 600 ++++++++++++
 .../tests/e2e/solr/DocLevelGenerator.java       |  16 +-
 .../tests/e2e/solr/DummyAuthPluginImpl.java     |  68 ++
 .../ModifiableUserAuthenticationFilter.java     |  73 --
 .../e2e/solr/TestCollAdminCoreOperations.java   | 145 ---
 .../tests/e2e/solr/TestDocLevelOperations.java  | 400 ++++----
 .../tests/e2e/solr/TestQueryOperations.java     |  78 --
 .../sentry/tests/e2e/solr/TestRealTimeGet.java  | 476 ----------
 .../sentry/tests/e2e/solr/TestSentryServer.java | 144 +++
 .../tests/e2e/solr/TestSolrAdminOperations.java | 188 ++++
 .../e2e/solr/TestSolrCollectionOperations.java  | 141 +++
 .../e2e/solr/TestSolrConfigOperations.java      | 232 +++++
 .../e2e/solr/TestSolrSchemaOperations.java      | 146 +++
 .../tests/e2e/solr/TestUpdateOperations.java    | 168 ----
 .../AbstractSolrSentryTestWithDbProvider.java   | 324 -------
 .../db/integration/TestSolrAdminOperations.java | 242 -----
 .../integration/TestSolrDocLevelOperations.java | 204 ----
 .../db/integration/TestSolrQueryOperations.java |  96 --
 .../integration/TestSolrUpdateOperations.java   | 100 --
 .../cloud-managed/conf/managed-schema           |  27 +
 .../cloud-managed/conf/solrconfig.xml           |  51 +
 .../configsets/cloud-minimal/conf/schema.xml    |  28 +
 .../cloud-minimal/conf/solrconfig.xml           |  47 +
 .../conf/schema.xml                             |  29 +
 .../conf/solrconfig.xml                         |  82 ++
 .../test/resources/solr/security/security.json  |  18 +
 133 files changed, 5438 insertions(+), 9048 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index bea2c5f..0d4fe0a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,7 +90,7 @@ limitations under the License.
     <pig.version>0.12.0</pig.version>
     <shiro.version>1.4.0</shiro.version>
     <slf4j.version>1.7.25</slf4j.version>
-    <solr.version>4.10.2</solr.version>
+    <solr.version>7.1.0</solr.version>
     <sqoop.version>1.99.7</sqoop.version>
     <surefire.version>2.20.1</surefire.version>
     <test.sentry.hadoop.classpath>${maven.test.classpath}</test.sentry.hadoop.classpath>
@@ -208,11 +208,6 @@ limitations under the License.
       </dependency>
       <dependency>
         <groupId>org.apache.sentry</groupId>
-        <artifactId>solr-sentry-core</artifactId>
-        <version>${project.version}</version>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.sentry</groupId>
         <artifactId>solr-sentry-handlers</artifactId>
         <version>${project.version}</version>
       </dependency>
@@ -394,7 +389,7 @@ limitations under the License.
       </dependency>
       <dependency>
         <groupId>org.apache.sentry</groupId>
-        <artifactId>sentry-core-model-search</artifactId>
+        <artifactId>sentry-core-model-solr</artifactId>
         <version>${project.version}</version>
       </dependency>
       <dependency>
@@ -643,9 +638,9 @@ limitations under the License.
     <module>sentry-binding</module>
     <module>sentry-provider</module>
     <module>sentry-policy</module>
+    <module>sentry-solr</module>
     <module>sentry-tests</module>
     <module>sentry-hdfs</module>
-    <module>sentry-solr</module>
     <module>sentry-dist</module>
   </modules>
 
@@ -849,6 +844,7 @@ limitations under the License.
                   <exclude>**.patch</exclude>
                   <!-- Exclude generated solr config files -->
                   <exclude>**/solr/collection1/conf/**</exclude>
+                  <exclude>**/solr/security/**</exclude>
                   <exclude>**/empty-file-main-lib.txt</exclude>
                   <!-- Exclude generated thrift files -->
                   <exclude>**/gen/**</exclude>

http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/sentry-binding/sentry-binding-solr/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/pom.xml b/sentry-binding/sentry-binding-solr/pom.xml
index ed2624b..2452e2f 100644
--- a/sentry-binding/sentry-binding-solr/pom.xml
+++ b/sentry-binding/sentry-binding-solr/pom.xml
@@ -30,17 +30,18 @@ limitations under the License.
 
   <dependencies>
     <dependency>
+      <groupId>org.apache.solr</groupId>
+      <artifactId>solr-core</artifactId>
+      <version>${solr.version}</version>
+    </dependency>
+    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.sentry</groupId>
-      <artifactId>sentry-core-common</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.sentry</groupId>
-      <artifactId>sentry-core-model-search</artifactId>
+      <artifactId>sentry-core-model-solr</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.sentry</groupId>

http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SentrySolrAuthorizationException.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SentrySolrAuthorizationException.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SentrySolrAuthorizationException.java
deleted file mode 100644
index 938dbfd..0000000
--- a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SentrySolrAuthorizationException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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;
-
-public class SentrySolrAuthorizationException extends Exception {
-  private static final long serialVersionUID = -263787088321897523L;
-
-  public SentrySolrAuthorizationException(String message) {
-    super(message);
-  }
-}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SentrySolrPluginImpl.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SentrySolrPluginImpl.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SentrySolrPluginImpl.java
new file mode 100644
index 0000000..c0ead28
--- /dev/null
+++ b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SentrySolrPluginImpl.java
@@ -0,0 +1,408 @@
+/*
+ * 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 static org.apache.sentry.binding.solr.authz.SolrAuthzBinding.QUERY;
+import static org.apache.sentry.binding.solr.authz.SolrAuthzBinding.UPDATE;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authentication.util.KerberosName;
+import org.apache.http.auth.BasicUserPrincipal;
+import org.apache.sentry.binding.solr.conf.SolrAuthzConf;
+import org.apache.sentry.core.common.Subject;
+import org.apache.sentry.core.model.solr.AdminOperation;
+import org.apache.sentry.core.model.solr.Collection;
+import org.apache.sentry.core.model.solr.SolrConstants;
+import org.apache.sentry.core.model.solr.SolrModelAction;
+import org.apache.sentry.core.model.solr.SolrModelAuthorizable;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.common.params.CoreAdminParams;
+import org.apache.solr.security.AuthorizationContext;
+import org.apache.solr.security.AuthorizationContext.CollectionRequest;
+import org.apache.solr.security.AuthorizationPlugin;
+import org.apache.solr.security.AuthorizationResponse;
+import org.apache.solr.security.PermissionNameProvider;
+import org.apache.solr.security.PermissionNameProvider.Name;
+import org.apache.solr.sentry.AuditLogger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * A concrete implementation of Solr {@linkplain AuthorizationPlugin} backed by Sentry.
+ *
+ */
+public class SentrySolrPluginImpl implements AuthorizationPlugin {
+  private static final Logger LOG = LoggerFactory.getLogger(SentrySolrPluginImpl.class);
+
+  /**
+   * A property specifies the value of the prefix to be used to define Java system property
+   * for configuring the authentication mechanism. The name of the Java system property is
+   * defined by appending the configuration parmeter namne to this prefix value e.g. if prefix
+   * is 'solr' then the Java system property 'solr.kerberos.principal' defines the value of
+   * configuration parameter 'kerberos.principal'.
+   */
+  private static final String SYSPROP_PREFIX_PROPERTY = "sysPropPrefix";
+
+  /**
+   * A property specifying the configuration parameters required by the Sentry authorization
+   * plugin.
+   */
+  private static final String AUTH_CONFIG_NAMES_PROPERTY = "authConfigs";
+
+  /**
+   * A property specifying the default values for the configuration parameters specified by the
+   * {@linkplain #AUTH_CONFIG_NAMES_PROPERTY} property. The default values are specified as a
+   * collection of key-value pairs (i.e. property-name : default_value).
+   */
+  private static final String DEFAULT_AUTH_CONFIGS_PROPERTY = "defaultConfigs";
+
+  /**
+   * A configuration property specifying location of sentry-site.xml
+   */
+  public static final String SNTRY_SITE_LOCATION_PROPERTY = "authorization.sentry.site";
+
+  /**
+   * A configuration property specifying the Solr super-user name. The Sentry permissions
+   * check will be skipped if the request is authenticated with this user name.
+   */
+  public static final String SENTRY_SOLR_AUTH_SUPERUSER = "authorization.superuser";
+
+  /**
+   * A configuration property to enable audit log for the Solr operations. Please note that
+   * audit log is available only for operations handled by the Solr authorization framework.
+   */
+  public static final String SENTRY_ENABLE_SOLR_AUDITLOG = "authorization.enable.auditlog";
+
+  /**
+   * A configuration property to specify the location of Hadoop configuration files (specifically
+   * core-site.xml) required to properly setup Hadoop {@linkplain UserGroupInformation} context.
+   */
+  public static final String SENTRY_HADOOP_CONF_DIR_PROPERTY = "authorization.sentry.hadoop.conf";
+
+  private String solrSuperUser;
+  private SolrAuthzBinding binding;
+  private Optional<AuditLogger> auditLog = Optional.empty();
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public void init(Map<String, Object> pluginConfig) {
+    Map<String, String> params = new HashMap<>();
+
+    String sysPropPrefix = (String) pluginConfig.getOrDefault(SYSPROP_PREFIX_PROPERTY, "solr.");
+    java.util.Collection<String> authConfigNames = (java.util.Collection<String>) pluginConfig.
+        getOrDefault(AUTH_CONFIG_NAMES_PROPERTY, Collections.emptyList());
+    Map<String,String> authConfigDefaults = (Map<String,String>) pluginConfig
+        .getOrDefault(DEFAULT_AUTH_CONFIGS_PROPERTY, Collections.emptyMap());
+
+    for ( String configName : authConfigNames) {
+      String systemProperty = sysPropPrefix + configName;
+      String defaultConfigVal = authConfigDefaults.get(configName);
+      String configVal = System.getProperty(systemProperty, defaultConfigVal);
+      if (configVal != null) {
+        params.put(configName, configVal);
+      }
+    }
+
+    initializeSentry(params);
+  }
+
+  @Override
+  public void close() throws IOException {
+    if (this.binding != null) {
+      this.binding.close();
+    }
+  }
+
+  @Override
+  public AuthorizationResponse authorize(AuthorizationContext authCtx) {
+    if (authCtx.getUserPrincipal() == null) { // Request not authenticated.
+      return AuthorizationResponse.PROMPT;
+    }
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Authorizing a request with authorization context {} ", SolrAuthzUtil.toString(authCtx));
+    }
+
+    String userNameStr = getShortUserName(authCtx.getUserPrincipal());
+
+    if (this.solrSuperUser.equals(userNameStr)) {
+      return AuthorizationResponse.OK;
+    }
+
+    if (authCtx.getHandler() instanceof PermissionNameProvider) {
+      Subject userName = new Subject(userNameStr);
+      Name perm = ((PermissionNameProvider) authCtx.getHandler()).getPermissionName(authCtx);
+      switch (perm) {
+        case READ_PERM:
+        case UPDATE_PERM: {
+          AuthorizationResponse resp = AuthorizationResponse.FORBIDDEN;
+          Set<SolrModelAction> actions = (perm == Name.READ_PERM) ? QUERY : UPDATE;
+          for (CollectionRequest req : authCtx.getCollectionRequests()) {
+            resp = binding.authorizeCollection(userName,
+                new Collection(req.collectionName), actions);
+            if (!AuthorizationResponse.OK.equals(resp)) {
+              break;
+            }
+          }
+
+          audit (perm, authCtx, resp);
+          return resp;
+        }
+        case SECURITY_EDIT_PERM: {
+          return binding.authorize(userName, Collections.singleton(AdminOperation.SECURITY), UPDATE);
+        }
+        case SECURITY_READ_PERM: {
+          return binding.authorize(userName, Collections.singleton(AdminOperation.SECURITY), QUERY);
+        }
+        case CORE_READ_PERM:
+        case CORE_EDIT_PERM:
+        case COLL_READ_PERM:
+        case COLL_EDIT_PERM: {
+          AuthorizationResponse resp = AuthorizationResponse.FORBIDDEN;
+          SolrModelAuthorizable auth = (perm == Name.COLL_READ_PERM || perm == Name.COLL_EDIT_PERM)
+              ? AdminOperation.COLLECTIONS : AdminOperation.CORES;
+          Set<SolrModelAction> actions = (perm == Name.COLL_READ_PERM || perm == Name.CORE_READ_PERM)
+              ? QUERY : UPDATE;
+          resp = binding.authorize(userName, Collections.singleton(auth), actions);
+          audit (perm, authCtx, resp);
+          if (AuthorizationResponse.OK.equals(resp)) {
+            // Apply collection/core-level permissions check as well.
+            for (Map.Entry<String, SolrModelAction> entry :
+              SolrAuthzUtil.getCollectionsForAdminOp(authCtx).entrySet()) {
+              resp = binding.authorizeCollection(userName,
+                  new Collection(entry.getKey()), Collections.singleton(entry.getValue()));
+              Name p = entry.getValue().equals(SolrModelAction.UPDATE) ? Name.UPDATE_PERM : Name.READ_PERM;
+              audit(p, authCtx, resp);
+              if (!AuthorizationResponse.OK.equals(resp)) {
+                break;
+              }
+            }
+          }
+          return resp;
+        }
+        case CONFIG_EDIT_PERM: {
+          return binding.authorize(userName, SolrAuthzUtil.getConfigAuthorizables(authCtx), UPDATE);
+        }
+        case CONFIG_READ_PERM: {
+          return binding.authorize(userName, SolrAuthzUtil.getConfigAuthorizables(authCtx), QUERY);
+        }
+        case SCHEMA_EDIT_PERM: {
+          return binding.authorize(userName, SolrAuthzUtil.getSchemaAuthorizables(authCtx), UPDATE);
+        }
+        case SCHEMA_READ_PERM: {
+          return binding.authorize(userName, SolrAuthzUtil.getSchemaAuthorizables(authCtx), QUERY);
+        }
+        case METRICS_READ_PERM: {
+          return binding.authorize(userName, Collections.singleton(AdminOperation.METRICS), QUERY);
+        }
+        case AUTOSCALING_READ_PERM:
+        case AUTOSCALING_HISTORY_READ_PERM: {
+          return binding.authorize(userName, Collections.singleton(AdminOperation.AUTOSCALING), QUERY);
+        }
+        case AUTOSCALING_WRITE_PERM: {
+          return binding.authorize(userName, Collections.singleton(AdminOperation.AUTOSCALING), UPDATE);
+        }
+        case ALL: {
+          return AuthorizationResponse.OK;
+        }
+      }
+    }
+
+    /*
+     * The switch-case statement above handles all possible permission types. Some of the request handlers
+     * in SOLR do not implement PermissionNameProvider interface and hence are incapable to providing the
+     * type of permission to be enforced for this request. This is a design limitation (or a bug) on the SOLR
+     * side. Until that issue is resolved, Solr/Sentry plugin needs to return OK for such requests.
+     * Ref: SOLR-11623
+     */
+    return AuthorizationResponse.OK;
+  }
+
+  /**
+   * This method returns the roles associated with the specified user name.
+   */
+  public Set<String> getRoles (String userName) {
+    return binding.getRoles(userName);
+  }
+
+  private void initializeSentry(Map<String, String> config) {
+    String sentrySiteLoc =
+        Preconditions.checkNotNull(config.get(SNTRY_SITE_LOCATION_PROPERTY),
+            "The authorization plugin configuration is missing " + SNTRY_SITE_LOCATION_PROPERTY
+            + " property");
+    String sentryHadoopConfLoc = (String)config.get(SENTRY_HADOOP_CONF_DIR_PROPERTY);
+
+    try {
+      List<URL> configFiles = getHadoopConfigFiles(sentryHadoopConfLoc);
+      configFiles.add((new File(sentrySiteLoc)).toURI().toURL());
+
+      binding = new SolrAuthzBinding(new SolrAuthzConf(configFiles));
+      LOG.info("SolrAuthzBinding created successfully");
+    } catch (Exception e) {
+      throw new SolrException(ErrorCode.SERVER_ERROR, "Unable to create SolrAuthzBinding", e);
+    }
+
+    this.solrSuperUser = Preconditions.checkNotNull(config.get(SENTRY_SOLR_AUTH_SUPERUSER));
+    boolean enableAuditLog = Boolean.parseBoolean(
+        Preconditions.checkNotNull(config.get(SENTRY_ENABLE_SOLR_AUDITLOG)));
+    if (enableAuditLog) {
+      this.auditLog = Optional.of(new AuditLogger());
+    }
+  }
+
+  private void audit (Name perm, AuthorizationContext ctx, AuthorizationResponse resp) {
+    if (!auditLog.isPresent() || !auditLog.get().isLogEnabled()) {
+      return;
+    }
+
+    String userName = getShortUserName(ctx.getUserPrincipal());
+    String ipAddress = ctx.getRemoteAddr();
+    long eventTime = System.currentTimeMillis();
+    int allowed = (resp.statusCode == AuthorizationResponse.OK.statusCode)
+        ? AuditLogger.ALLOWED : AuditLogger.UNAUTHORIZED;
+    String operationParams = ctx.getParams().toString();
+
+    switch (perm) {
+      case COLL_EDIT_PERM:
+      case COLL_READ_PERM: {
+        String collectionName = "admin";
+        String actionName = ctx.getParams().get(CoreAdminParams.ACTION);
+        String operationName = (actionName != null) ?
+            "CollectionAction." + ctx.getParams().get(CoreAdminParams.ACTION)
+            : ctx.getHandler().getClass().getName();
+        auditLog.get().log (userName, null, ipAddress,
+            operationName, operationParams, eventTime, allowed, collectionName);
+        break;
+      }
+
+      case CORE_EDIT_PERM:
+      case CORE_READ_PERM: {
+        String collectionName = "admin";
+        String operationName = "CoreAdminAction.STATUS";
+        if (ctx.getParams().get(CoreAdminParams.ACTION) != null) {
+          operationName = "CoreAdminAction." + ctx.getParams().get(CoreAdminParams.ACTION);
+        }
+
+        auditLog.get().log (userName, null, ipAddress,
+            operationName, operationParams, eventTime, allowed, collectionName);
+        break;
+      }
+
+      case READ_PERM:
+      case UPDATE_PERM: {
+        List<String> names = new ArrayList<>();
+        for (CollectionRequest r : ctx.getCollectionRequests()) {
+          names.add(r.collectionName);
+        }
+        String collectionName = String.join(",", names);
+        String operationName = (perm == Name.READ_PERM) ? SolrConstants.QUERY : SolrConstants.UPDATE;
+        auditLog.get().log (userName, null, ipAddress,
+            operationName, operationParams, eventTime, allowed, collectionName);
+        break;
+      }
+
+      default: {
+        // Do nothing.
+        break;
+      }
+    }
+  }
+
+  /**
+   * Workaround until SOLR-10814 is fixed. This method allows extracting short user-name from
+   * Solr provided {@linkplain Principal} instance.
+   *
+   * @param ctx The Solr provided authorization context
+   * @return The short name of the authenticated user for this request
+   */
+  public static String getShortUserName (Principal princ) {
+    if (princ instanceof BasicUserPrincipal) {
+      return  princ.getName();
+    }
+
+    KerberosName name = new KerberosName(princ.getName());
+    try {
+      return name.getShortName();
+    } catch (IOException e) {
+      LOG.error("Error converting kerberos name. principal = {}, KerberosName.rules = {}",
+                                princ, KerberosName.getRules());
+      throw new SolrException(ErrorCode.SERVER_ERROR, "Unexpected error converting a kerberos name", e);
+    }
+  }
+
+  /**
+   * This method provides the path(s) of various Hadoop configuration files required
+   * by the Sentry/Solr plugin.
+   * @param confDir Location of a folder (on local file-system) storing Sentry Hadoop
+   *                configuration files
+   * @return A list of URLs containing the Sentry Hadoop
+   *                configuration files
+   */
+  private List<URL> getHadoopConfigFiles(String confDir) {
+    List<URL> result = new ArrayList<>();
+
+    if (confDir != null && !confDir.isEmpty()) {
+      File confDirFile = new File(confDir);
+      if (!confDirFile.exists()) {
+        throw new SolrException(ErrorCode.SERVER_ERROR,
+            "Specified Sentry hadoop config directory does not exist: "
+               + confDirFile.getAbsolutePath());
+      }
+      if (!confDirFile.isDirectory()) {
+        throw new SolrException(ErrorCode.SERVER_ERROR,
+            "Specified Sentry hadoop config directory path is not a directory: "
+               + confDirFile.getAbsolutePath());
+      }
+      if (!confDirFile.canRead()) {
+        throw new SolrException(ErrorCode.SERVER_ERROR,
+            "Specified Sentry hadoop config directory must be readable by the Solr process: "
+               + confDirFile.getAbsolutePath());
+      }
+
+      for (String file : Arrays.asList("core-site.xml",
+          "hdfs-site.xml", "ssl-client.xml")) {
+        File f = new File(confDirFile, file);
+        if (f.exists()) {
+          try {
+            result.add(f.toURI().toURL());
+          } catch (MalformedURLException e) {
+            throw new SolrException(ErrorCode.SERVER_ERROR, e.getMessage(), e);
+          }
+        }
+      }
+    }
+
+    return result;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java
index 0a818e5..803e5ea 100644
--- a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java
+++ b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzBinding.java
@@ -16,81 +16,80 @@
  */
 package org.apache.sentry.binding.solr.authz;
 
-import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION;
-import static org.apache.sentry.core.model.search.SearchConstants.SENTRY_SEARCH_SERVICE_DEFAULT;
-import static org.apache.sentry.core.model.search.SearchConstants.SENTRY_SEARCH_SERVICE_KEY;
-import static org.apache.sentry.core.model.search.SearchModelAuthorizable.AuthorizableType.Collection;
+import static org.apache.sentry.core.model.solr.SolrConstants.SENTRY_SOLR_SERVICE_DEFAULT;
+import static org.apache.sentry.core.model.solr.SolrConstants.SENTRY_SOLR_SERVICE_KEY;
 
-import java.io.File;
+import java.io.Closeable;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.util.Arrays;
-import java.util.List;
+import java.util.Collections;
+import java.util.HashSet;
 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.core.common.exception.SentryUserException;
 import org.apache.sentry.binding.solr.conf.SolrAuthzConf;
 import org.apache.sentry.binding.solr.conf.SolrAuthzConf.AuthzConfVars;
-import org.apache.sentry.core.common.Action;
 import org.apache.sentry.core.common.ActiveRoleSet;
+import org.apache.sentry.core.common.Authorizable;
 import org.apache.sentry.core.common.Model;
 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.core.model.search.SearchPrivilegeModel;
+import org.apache.sentry.core.model.solr.SolrPrivilegeModel;
+import org.apache.sentry.core.model.solr.AdminOperation;
+import org.apache.sentry.core.model.solr.Collection;
+import org.apache.sentry.core.model.solr.SolrModelAction;
+import org.apache.sentry.core.model.solr.SolrModelAuthorizable;
 import org.apache.sentry.policy.common.PolicyEngine;
 import org.apache.sentry.provider.common.AuthorizationComponent;
 import org.apache.sentry.provider.common.AuthorizationProvider;
-import org.apache.sentry.provider.common.GroupMappingService;
 import org.apache.sentry.provider.common.HadoopGroupResourceAuthorizationProvider;
 import org.apache.sentry.provider.common.ProviderBackend;
 import org.apache.sentry.provider.common.ProviderBackendContext;
+import org.apache.sentry.provider.common.GroupMappingService;
 import org.apache.sentry.provider.db.generic.SentryGenericProviderBackend;
 import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient;
 import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClientFactory;
-import org.apache.sentry.provider.db.generic.service.thrift.TAuthorizable;
-import org.apache.sentry.provider.db.generic.service.thrift.TSentryGrantOption;
-import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege;
 import org.apache.sentry.provider.db.generic.tools.GenericPrivilegeConverter;
 import org.apache.sentry.service.thrift.ServiceConstants;
+import org.apache.solr.security.AuthorizationResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-
-public class SolrAuthzBinding {
+/**
+ * This class provides functionality to initialize the Sentry (specifically
+ * {@linkplain AuthorizationProvider} and {@linkplain ProviderBackend}) as
+ * well as query the permissions for a given user and a specific set of
+ * entities.
+ */
+public class SolrAuthzBinding implements Closeable {
   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 SOLR_POLICY_ENGINE_OLD = "org.apache.sentry.policy.search.SimpleSearchPolicyEngine";
-  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;
+
+  static final Set<SolrModelAction> QUERY = new HashSet<>(Arrays.asList(SolrModelAction.QUERY));
+  static final Set<SolrModelAction> UPDATE = new HashSet<>(Arrays.asList(SolrModelAction.UPDATE));
 
   private final SolrAuthzConf authzConf;
-  private final AuthorizationProvider authProvider;
+  public final AuthorizationProvider authProvider;
   private final GroupMappingService groupMapping;
-  private ProviderBackend providerBackend;
-  private Subject bindingSubject;
+  public ProviderBackend providerBackend;
 
-  public SolrAuthzBinding (SolrAuthzConf authzConf) throws Exception {
-    this.authzConf = addHdfsPropsToConf(authzConf);
+  /**
+   * The constructor.
+   *
+   * @param authzConf The Sentry/Solr authorization configuration
+   * @throws Exception in case of errors.
+   */
+  public SolrAuthzBinding(SolrAuthzConf authzConf) throws Exception {
+    this.authzConf = authzConf;
     this.authProvider = getAuthProvider();
     this.groupMapping = authProvider.getGroupMapping();
-    /**
-     * The Solr server principal will use the binding
-     */
-    this.bindingSubject = new Subject(UserGroupInformation.getCurrentUser()
-        .getShortUserName());
+  }
+
+  @Override
+  public void close() throws IOException {
+    if (this.authProvider != null) {
+      this.authProvider.close();
+    }
   }
 
   // Instantiate the configured authz provider
@@ -103,36 +102,18 @@ public class SolrAuthzBinding {
         authzConf.get(AuthzConfVars.AUTHZ_PROVIDER_BACKEND.getVar());
     String policyEngineName =
         authzConf.get(AuthzConfVars.AUTHZ_POLICY_ENGINE.getVar(), AuthzConfVars.AUTHZ_POLICY_ENGINE.getDefault());
-    String serviceName = authzConf.get(SENTRY_SEARCH_SERVICE_KEY, SENTRY_SEARCH_SERVICE_DEFAULT);
-
-    // for the backward compatibility
-    if (SOLR_POLICY_ENGINE_OLD.equals(policyEngineName)) {
-      policyEngineName = AuthzConfVars.AUTHZ_POLICY_ENGINE.getDefault();
-    }
+    String serviceName = authzConf.get(SENTRY_SOLR_SERVICE_KEY, SENTRY_SOLR_SERVICE_DEFAULT);
 
     LOG.debug("Using authorization provider " + authProviderName +
         " with resource " + resourceName + ", policy engine "
         + policyEngineName + ", provider backend " + providerBackendName);
-    // load the provider backend class
-    if (kerberosEnabledProp.equalsIgnoreCase("true")) {
-      initKerberos(keytabProp, principalProp);
-    } else {
-      // set configuration so that group mappings are properly setup even if
-      // we don't use kerberos, for testing
-      UserGroupInformation.setConfiguration(authzConf);
-    }
 
     // for convenience, set the PrivilegeConverter.
     if (authzConf.get(ServiceConstants.ClientConfig.PRIVILEGE_CONVERTER) == null) {
-      authzConf.set(ServiceConstants.ClientConfig.PRIVILEGE_CONVERTER, GenericPrivilegeConverter.class.getName());
+      authzConf.set(ServiceConstants.ClientConfig.PRIVILEGE_CONVERTER,
+                       GenericPrivilegeConverter.class.getName());
     }
 
-    // the SearchProviderBackend is deleted in SENTRY-828, this is for the compatible with the
-    // previous Sentry.
-    if ("org.apache.sentry.provider.db.generic.service.thrift.SearchProviderBackend"
-        .equals(providerBackendName)) {
-      providerBackendName = SentryGenericProviderBackend.class.getName();
-    }
     Constructor<?> providerBackendConstructor =
         Class.forName(providerBackendName).getDeclaredConstructor(Configuration.class, String.class);
     providerBackendConstructor.setAccessible(true);
@@ -142,14 +123,14 @@ public class SolrAuthzBinding {
 
     if (providerBackend instanceof SentryGenericProviderBackend) {
       ((SentryGenericProviderBackend) providerBackend)
-          .setComponentType(AuthorizationComponent.Search);
+      .setComponentType(AuthorizationComponent.Search);
       ((SentryGenericProviderBackend) providerBackend).setServiceName(serviceName);
     }
 
     // Create backend context
     ProviderBackendContext context = new ProviderBackendContext();
     context.setAllowPerDatabase(false);
-    context.setValidators(SearchPrivilegeModel.getInstance().getPrivilegeValidators());
+    context.setValidators(SolrPrivilegeModel.getInstance().getPrivilegeValidators());
     providerBackend.initialize(context);
 
     // load the policy engine class
@@ -167,34 +148,63 @@ public class SolrAuthzBinding {
 
     // load the authz provider class
     Constructor<?> constrctor =
-      Class.forName(authProviderName).getDeclaredConstructor(Configuration.class,
-              String.class, PolicyEngine.class, Model.class);
+        Class.forName(authProviderName).getDeclaredConstructor(Configuration.class,
+            String.class, PolicyEngine.class, Model.class);
     constrctor.setAccessible(true);
     return (AuthorizationProvider) constrctor.newInstance(new Object[] {authzConf, resourceName,
-            policyEngine, SearchPrivilegeModel.getInstance()});
+        policyEngine, SolrPrivilegeModel.getInstance()});
   }
 
-
   /**
-   * Authorize access to an index/collection
-   * @param subject
-   * @param collection
-   * @param actions
-   * @throws SentrySolrAuthorizationException
+   * Authorize access to a Solr operation
+   * @param subject The user invoking the SOLR operation
+   * @param admin The {@linkplain SolrModelAuthorizable} associated with the operation
+   * @param actions The action performed as part of the operation (query or update)
+   * @return {@linkplain AuthorizationResponse#OK} If the authorization is successful
+   *         {@linkplain AuthorizationResponse#FORBIDDEN} if the authorization fails.
    */
-  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() +
+  public AuthorizationResponse authorize (Subject subject,
+      java.util.Collection<? extends SolrModelAuthorizable> authorizables, Set<SolrModelAction> actions) {
+    if(LOG.isDebugEnabled()) {
+      LOG.debug("Going to authorize " + authorizables +
           " 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());
+    for (SolrModelAuthorizable a : authorizables) {
+      if (!authProvider.hasAccess(subject, Arrays.asList(new Authorizable[] { a }),
+          actions, ActiveRoleSet.ALL)) {
+        return AuthorizationResponse.FORBIDDEN;
+      }
     }
+
+    return AuthorizationResponse.OK;
+  }
+
+  /**
+   * Authorize access to an index/collection
+   * @param subject The user invoking the SOLR collection related operation
+   * @param collection The Solr collection associated with the operation
+   * @param actions The action performed as part of the operation (query or update)
+   * @return {@linkplain AuthorizationResponse#OK} If the authorization is successful
+   *         {@linkplain AuthorizationResponse#FORBIDDEN} if the authorization fails.
+   */
+  public AuthorizationResponse authorizeCollection(Subject subject, Collection collection,
+      Set<SolrModelAction> actions) {
+    return authorize(subject, Collections.singleton(collection), actions);
+  }
+
+  /**
+   * Authorize access to an admin operation
+   * @param subject The user invoking the SOLR admin operation
+   * @param admin The type of the admin operation
+   * @param actions The action performed as part of the operation (query or update)
+   * @return {@linkplain AuthorizationResponse#OK} If the authorization is successful
+   *         {@linkplain AuthorizationResponse#FORBIDDEN} if the authorization fails.
+   */
+  public AuthorizationResponse authorizeAdminAction(Subject subject, AdminOperation admin,
+      Set<SolrModelAction> actions) {
+    return authorize(subject, Collections.singleton(admin), actions);
   }
 
   /**
@@ -217,103 +227,7 @@ public class SolrAuthzBinding {
     return providerBackend.getRoles(getGroups(user), ActiveRoleSet.ALL);
   }
 
-  private SolrAuthzConf addHdfsPropsToConf(SolrAuthzConf conf) throws IOException {
-    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 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 = Boolean.TRUE;
-        final String authVal = authzConf.get(HADOOP_SECURITY_AUTHENTICATION);
-        final String kerberos = "kerberos";
-        if (authVal != null && !authVal.equals(kerberos)) {
-          throw new IllegalArgumentException(HADOOP_SECURITY_AUTHENTICATION
-              + " set to: " + authVal + ", not kerberos, but attempting to "
-              + " connect to HDFS via kerberos");
-        }
-        // let's avoid modifying the supplied configuration, just to be conservative
-        final Configuration ugiConf = new Configuration(authzConf);
-        ugiConf.set(HADOOP_SECURITY_AUTHENTICATION, kerberos);
-        UserGroupInformation.setConfiguration(ugiConf);
-        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");
-      }
-    }
-  }
-
-  /**
-   * SENTRY-478
-   * If the binding uses the searchProviderBackend, it can sync privilege with Sentry Service
-   */
-  public boolean isSyncEnabled() {
-    return providerBackend instanceof SentryGenericProviderBackend;
-  }
-
   public SentryGenericServiceClient getClient() throws Exception {
     return SentryGenericServiceClientFactory.create(authzConf);
   }
-
-  /**
-   * Attempt to notify the Sentry service when deleting collection happened
-   * @param collection
-   * @throws SolrException
-   */
-  public void deleteCollectionPrivilege(String collection) throws SentrySolrAuthorizationException {
-    if (!isSyncEnabled()) {
-      return;
-    }
-    try (SentryGenericServiceClient client = getClient()) {
-      TSentryPrivilege tPrivilege = new TSentryPrivilege();
-      tPrivilege.setComponent(AuthorizationComponent.Search);
-      tPrivilege.setServiceName(authzConf.get(SENTRY_SEARCH_SERVICE_KEY,
-          SENTRY_SEARCH_SERVICE_DEFAULT));
-      tPrivilege.setAction(Action.ALL);
-      tPrivilege.setGrantOption(TSentryGrantOption.UNSET);
-      List<TAuthorizable> authorizables = Lists.newArrayList(new TAuthorizable(Collection.name(),
-          collection));
-      tPrivilege.setAuthorizables(authorizables);
-      client.dropPrivilege(bindingSubject.getName(), AuthorizationComponent.Search, tPrivilege);
-    } catch (SentryUserException ex) {
-      throw new SentrySolrAuthorizationException("User " + bindingSubject.getName() +
-          " can't delete privileges for collection " + collection);
-    } catch (Exception ex) {
-      throw new SentrySolrAuthorizationException("Unable to obtain client:" + ex.getMessage());
-    }
-  }
 }

http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzUtil.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzUtil.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzUtil.java
new file mode 100644
index 0000000..42dce03
--- /dev/null
+++ b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/authz/SolrAuthzUtil.java
@@ -0,0 +1,271 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.sentry.core.model.solr.Config;
+import org.apache.sentry.core.model.solr.Schema;
+import org.apache.sentry.core.model.solr.SolrModelAction;
+import org.apache.solr.common.params.CollectionParams.CollectionAction;
+import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
+import org.apache.solr.common.params.CollectionAdminParams;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.CoreAdminParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.handler.admin.ConfigSetsHandler;
+import org.apache.solr.security.AuthorizationContext;
+import org.apache.solr.security.AuthorizationContext.CollectionRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Solr authorization framework does not currently support fine-grained authorization.
+ * Specifically it does not provide the resource names consistently. This utility class
+ * extracts the resource names for specific APIs by introspecting the {@linkplain SolrParams}
+ * passed as part of {@linkplain AuthorizationContext}. This class can be removed once SOLR-11543
+ * is available.
+ */
+class SolrAuthzUtil {
+  private static final Logger LOG = LoggerFactory.getLogger(SolrAuthzUtil.class);
+
+  /**
+   * This method returns a collection of {@linkplain Config} entities associated with the current
+   * operation.
+   */
+  static Collection<Config> getConfigAuthorizables (AuthorizationContext ctx) {
+    List<Config> result = new ArrayList<>(1);
+    if (ctx.getHandler() instanceof ConfigSetsHandler) { // For Solr configset APIs
+      String name = ctx.getParams().get(CommonParams.NAME);
+      if (name != null) {
+        result.add(new Config(name));
+      }
+    } else { // For Solr config APIs
+      for (CollectionRequest r : ctx.getCollectionRequests()) {
+        result.add(new Config(r.collectionName));
+      }
+    }
+    if (result.isEmpty()) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Missing collection name for the config operation with authorization context {}."
+            + " Using * permissions for authorization check", toString(ctx));
+      }
+      result.add(Config.ALL);
+    }
+
+    return result;
+  }
+
+  /**
+   * This method returns a collection of {@linkplain Schema} entities associated with the current
+   * operation.
+   */
+  static Collection<Schema> getSchemaAuthorizables (AuthorizationContext ctx) {
+    List<Schema> result = new ArrayList<>(1);
+    for (CollectionRequest r : ctx.getCollectionRequests()) {
+      result.add(new Schema(r.collectionName));
+    }
+    if (result.isEmpty()) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Missing collection name for the schema operation with authorization context {}."
+            + " Using * permissions for authorization check", toString(ctx));
+      }
+      result.add(Schema.ALL);
+    }
+
+    return result;
+  }
+
+  /**
+   * This method extracts the {@linkplain org.apache.sentry.core.model.solr.Collection} entities
+   * associated with this admin request and return a mapping of entity_name -> expected_auth_action.
+   * This is used by Solr/Sentry authorization plugin to further restrict Solr admin operations.
+   */
+  static Map<String, SolrModelAction> getCollectionsForAdminOp(AuthorizationContext ctx) {
+    String actionName = ctx.getParams().get(CoreAdminParams.ACTION);
+    CollectionAction action = CollectionAction.get(actionName);
+    if (action != null) {
+      switch (action) {
+        case LISTSNAPSHOTS:
+        case BACKUP: {
+          String name = ctx.getParams().get(CollectionAdminParams.COLLECTION);
+          return (name != null) ? Collections.singletonMap(name, SolrModelAction.QUERY)
+                                  : Collections.emptyMap();
+        }
+
+        case MIGRATE: {
+          Map<String, SolrModelAction> result = new HashMap<>();
+          String source = ctx.getParams().get(CollectionAdminParams.COLLECTION);
+          String target = ctx.getParams().get("target."+CollectionAdminParams.COLLECTION);
+          if (source != null) {
+            result.put (source, SolrModelAction.QUERY);
+          }
+          if (target != null) {
+            result.put (source, SolrModelAction.UPDATE);
+          }
+          return result;
+        }
+
+        case DELETE:
+        case DELETEALIAS:
+        case CREATESHARD:
+        case DELETESHARD:
+        case SPLITSHARD:
+        case RELOAD:
+        case CREATE: {
+          String name = ctx.getParams().get(CommonParams.NAME);
+          return (name != null) ? Collections.singletonMap(name, SolrModelAction.UPDATE)
+                                  : Collections.emptyMap();
+        }
+
+        case DELETESNAPSHOT:
+        case CREATESNAPSHOT:
+        case SYNCSHARD:
+        case MOVEREPLICA:
+        case RESTORE:
+        case MIGRATESTATEFORMAT:
+        case FORCELEADER:
+        case REBALANCELEADERS:
+        case BALANCESHARDUNIQUE:
+        case ADDREPLICAPROP:
+        case DELETEREPLICAPROP:
+        case ADDREPLICA:
+        case DELETEREPLICA:
+        case MODIFYCOLLECTION: {
+          String name = ctx.getParams().get(CollectionAdminParams.COLLECTION);
+          return (name != null) ? Collections.singletonMap(name, SolrModelAction.UPDATE)
+                                  : Collections.emptyMap();
+        }
+
+        case MOCK_COLL_TASK:
+        case MOCK_REPLICA_TASK:
+        case MOCK_SHARD_TASK:
+        case REPLACENODE:
+        case DELETENODE:
+        case ADDROLE:
+        case REMOVEROLE:
+        case CREATEALIAS:
+        case REQUESTSTATUS:
+        case DELETESTATUS:
+        case LIST:
+        case LISTALIASES:
+        case CLUSTERPROP:
+        case OVERSEERSTATUS:
+        case CLUSTERSTATUS: {
+          return Collections.emptyMap();
+        }
+      }
+    }
+
+    return Collections.emptyMap();
+  }
+
+  /**
+   * This method extracts the {@linkplain org.apache.sentry.core.model.solr.Collection} entities
+   * associated with this admin request and return a mapping of entity_name -> expected_auth_action.
+   * This is used by Solr/Sentry authorization plugin to further restrict Solr admin operations.
+   */
+  static Map<String, SolrModelAction> getCoresForAdminOp(AuthorizationContext ctx) {
+    String actionName = ctx.getParams().get(CoreAdminParams.ACTION);
+    CoreAdminAction action = CoreAdminAction.get(actionName);
+    if (action != null) {
+      switch (action) {
+        case REQUESTBUFFERUPDATES:
+        case REQUESTAPPLYUPDATES:
+        case CREATE: {
+          String coreName = ctx.getParams().get(CoreAdminParams.NAME);
+          return (coreName != null) ? Collections.singletonMap(coreName, SolrModelAction.UPDATE)
+                                  : Collections.emptyMap();
+        }
+
+        case REQUESTSTATUS:
+        case OVERSEEROP:
+        case INVOKE:
+        // TODO - is this correct ?
+        case DELETEALIAS: {
+          return Collections.emptyMap();
+        }
+
+        case REQUESTSYNCSHARD:
+        case REJOINLEADERELECTION:
+        case PREPRECOVERY:
+        case FORCEPREPAREFORLEADERSHIP:
+        case CREATESNAPSHOT:
+        case DELETESNAPSHOT:
+        case RESTORECORE:
+        case REQUESTRECOVERY:
+        case SPLIT:
+        case MERGEINDEXES:
+        case UNLOAD:
+        case RENAME:
+        case RELOAD: {
+          String coreName = ctx.getParams().get(CoreAdminParams.CORE);
+          return (coreName != null) ? Collections.singletonMap(coreName, SolrModelAction.UPDATE)
+                                  : Collections.emptyMap();
+        }
+
+        case LISTSNAPSHOTS:
+        case BACKUPCORE:
+        case STATUS: {
+          String coreName = ctx.getParams().get(CoreAdminParams.CORE);
+          return (coreName != null) ? Collections.singletonMap(coreName, SolrModelAction.QUERY)
+                                  : Collections.emptyMap();
+        }
+        case SWAP: {
+          Map<String, SolrModelAction> result = new HashMap<>();
+          String core1 = ctx.getParams().get(CoreAdminParams.CORE);
+          String core2 = ctx.getParams().get("other");
+          if (core1 != null) {
+            result.put(core1, SolrModelAction.UPDATE);
+          }
+          if (core2 != null) {
+            result.put(core2, SolrModelAction.UPDATE);
+          }
+          return result;
+        }
+      }
+    }
+
+    return Collections.emptyMap();
+  }
+
+
+  static String toString(AuthorizationContext ctx) {
+    StringBuilder builder = new StringBuilder();
+    builder.append("AuthorizationContext {");
+    builder.append("userPrincipal : ");
+    builder.append(ctx.getUserPrincipal().getName());
+    // NOTE - comment out the code until SOLR-10814 is fixed.
+    //builder.append(", userName : ");
+    //builder.append(ctx.getUserName());
+    builder.append(", collections : ");
+    builder.append(ctx.getCollectionRequests());
+    builder.append(", handler : ");
+    builder.append(ctx.getHandler());
+    builder.append(", HTTP method : ");
+    builder.append(ctx.getHttpMethod());
+    builder.append("}");
+
+    return builder.toString();
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java
index 37efa5b..0883e70 100644
--- a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java
+++ b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/sentry/binding/solr/conf/SolrAuthzConf.java
@@ -18,6 +18,7 @@ package org.apache.sentry.binding.solr.conf;
 
 import java.net.URL;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.hadoop.conf.Configuration;
@@ -71,14 +72,21 @@ public class SolrAuthzConf extends Configuration {
     currentToDeprecatedProps.put(AuthzConfVars.AUTHZ_PROVIDER.getVar(), AuthzConfVars.AUTHZ_PROVIDER_DEPRECATED);
   }
 
-  @SuppressWarnings("unused")
   private static final Logger LOG = LoggerFactory
       .getLogger(SolrAuthzConf.class);
   public static final String AUTHZ_SITE_FILE = "sentry-site.xml";
 
-  public SolrAuthzConf(URL solrAuthzSiteURL) {
+  /**
+   * This constructor allows configuration of Sentry including sentry-site.xml and core-site.xml
+   *
+   * @param sentryConf Location of a folder (on local file-system) storing
+   *                   sentry Hadoop configuration files
+   */
+  public SolrAuthzConf(List<URL> sentryConf) {
     super(true);
-    addResource(solrAuthzSiteURL);
+    for (URL u : sentryConf) {
+      addResource(u);
+    }
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/sentry-binding/sentry-binding-solr/src/main/java/org/apache/solr/sentry/AuditLogger.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/solr/sentry/AuditLogger.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/solr/sentry/AuditLogger.java
new file mode 100644
index 0000000..fc85769
--- /dev/null
+++ b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/solr/sentry/AuditLogger.java
@@ -0,0 +1,92 @@
+/*
+ * 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.solr.sentry;
+
+import org.apache.lucene.util.Version;
+import org.noggit.CharArr;
+import org.noggit.JSONWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Writes audit events to the audit log. This helps answer questions such as:
+ * Who did what action when from where, and what values were changed from what
+ * to what as a result?
+ */
+public final class AuditLogger {
+
+  public static final int ALLOWED = 1;
+  public static final int UNAUTHORIZED = 0;
+
+  private final Logger logger;
+
+  private static final String SOLR_VERSION = Version.LATEST.toString();
+
+
+  public AuditLogger() {
+    this.logger = LoggerFactory.getLogger(getClass());
+  }
+
+  public boolean isLogEnabled() {
+    return logger.isInfoEnabled();
+  }
+
+  public void log(
+    String userName,
+    String impersonator,
+    String ipAddress,
+    String operation,
+    String operationParams,
+    long eventTime,
+    int allowed,
+    String collectionName) {
+
+    if (!isLogEnabled()) {
+      return;
+    }
+    CharArr chars = new CharArr(512);
+    JSONWriter writer = new JSONWriter(chars, -1);
+    writer.startObject();
+    writeField("solrVersion", SOLR_VERSION, writer);
+    writer.writeValueSeparator();
+    writeField("eventTime", eventTime, writer);
+    writer.writeValueSeparator();
+    writeField("allowed", allowed, writer);
+    writer.writeValueSeparator();
+    writeField("collectionName", collectionName, writer);
+    writer.writeValueSeparator();
+    writeField("operation", operation, writer);
+    writer.writeValueSeparator();
+    writeField("operationParams", operationParams, writer);
+    writer.writeValueSeparator();
+    writeField("ipAddress", ipAddress, writer);
+    writer.writeValueSeparator();
+    writeField("username", userName, writer);
+    writer.writeValueSeparator();
+    writeField("impersonator", impersonator, writer);
+    writer.endObject();
+    logger.info("{}", chars);
+  }
+
+  private void writeField(String key, Object value, JSONWriter writer) {
+    writer.writeString(key);
+    writer.writeNameSeparator();
+    writer.write(value);
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/sentry-binding/sentry-binding-solr/src/main/java/org/apache/solr/sentry/RollingFileWithoutDeleteAppender.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/main/java/org/apache/solr/sentry/RollingFileWithoutDeleteAppender.java b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/solr/sentry/RollingFileWithoutDeleteAppender.java
new file mode 100644
index 0000000..a5dc8c3
--- /dev/null
+++ b/sentry-binding/sentry-binding-solr/src/main/java/org/apache/solr/sentry/RollingFileWithoutDeleteAppender.java
@@ -0,0 +1,182 @@
+/**
+ * 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.solr.sentry;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.Writer;
+import org.apache.log4j.FileAppender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.RollingFileAppender;
+import org.apache.log4j.helpers.CountingQuietWriter;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This class extends {@linkplain FileAppender} such that the log
+ * files are not deleted automatically (as done by {@linkplain RollingFileAppender}.
+ * It is responsibility of external process to consume these log files
+ * and delete them afterwards. This class should be used to provide audit log
+ * capability for Solr.
+ */
+public class RollingFileWithoutDeleteAppender extends FileAppender {
+  /**
+   * The default maximum file size is 10MB.
+   */
+  protected long maxFileSize = 10 * 1024 * 1024;
+
+  private long nextRollover = 0;
+
+  /**
+   * The default constructor simply calls its {@link FileAppender#FileAppender
+   * parents constructor}.
+   */
+  public RollingFileWithoutDeleteAppender() {
+    super();
+  }
+
+  /**
+   * Instantiate a RollingFileAppender and open the file designated by
+   * <code>filename</code>. The opened filename will become the ouput
+   * destination for this appender.
+   * <p>
+   * If the <code>append</code> parameter is true, the file will be appended to.
+   * Otherwise, the file desginated by <code>filename</code> will be truncated
+   * before being opened.
+   */
+  public RollingFileWithoutDeleteAppender(Layout layout, String filename,
+      boolean append) throws IOException {
+    super(layout, getLogFileName(filename), append);
+  }
+
+  /**
+   * Instantiate a FileAppender and open the file designated by
+   * <code>filename</code>. The opened filename will become the output
+   * destination for this appender.
+   * <p>
+   * The file will be appended to.
+   */
+  public RollingFileWithoutDeleteAppender(Layout layout, String filename)
+      throws IOException {
+    super(layout, getLogFileName(filename));
+  }
+
+  /**
+   * Get the maximum size that the output file is allowed to reach before being
+   * rolled over to backup files.
+   */
+  public long getMaximumFileSize() {
+    return maxFileSize;
+  }
+
+  /**
+   * Implements the usual roll over behaviour.
+   * <p>
+   * <code>File</code> is renamed <code>File.yyyyMMddHHmmss</code> and closed. A
+   * new <code>File</code> is created to receive further log output.
+   */
+  // synchronization not necessary since doAppend is alreasy synched
+  public void rollOver() {
+    if (qw != null) {
+      long size = ((CountingQuietWriter) qw).getCount();
+      LogLog.debug("rolling over count=" + size);
+      // if operation fails, do not roll again until
+      // maxFileSize more bytes are written
+      nextRollover = size + maxFileSize;
+    }
+
+    this.closeFile(); // keep windows happy.
+
+    String newFileName = getLogFileName(fileName);
+    try {
+      // This will also close the file. This is OK since multiple
+      // close operations are safe.
+      this.setFile(newFileName, false, bufferedIO, bufferSize);
+      nextRollover = 0;
+    } catch (IOException e) {
+      if (e instanceof InterruptedIOException) {
+        Thread.currentThread().interrupt();
+      }
+      LogLog.error("setFile(" + newFileName + ", false) call failed.", e);
+    }
+  }
+
+  public synchronized void setFile(String fileName, boolean append,
+      boolean bufferedIO, int bufferSize) throws IOException {
+    super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
+    if (append) {
+      File f = new File(fileName);
+      ((CountingQuietWriter) qw).setCount(f.length());
+    }
+  }
+
+  /**
+   * Set the maximum size that the output file is allowed to reach before being
+   * rolled over to backup files.
+   * <p>
+   * This method is equivalent to {@link #setMaxFileSize} except that it is
+   * required for differentiating the setter taking a <code>long</code> argument
+   * from the setter taking a <code>String</code> argument by the JavaBeans
+   * {@link java.beans.Introspector Introspector}.
+   *
+   * @see #setMaxFileSize(String)
+   */
+  public void setMaximumFileSize(long maxFileSize) {
+    this.maxFileSize = maxFileSize;
+  }
+
+  /**
+   * Set the maximum size that the output file is allowed to reach before being
+   * rolled over to backup files.
+   * <p>
+   * In configuration files, the <b>MaxFileSize</b> option takes an long integer
+   * in the range 0 - 2^63. You can specify the value with the suffixes "KB",
+   * "MB" or "GB" so that the integer is interpreted being expressed
+   * respectively in kilobytes, megabytes or gigabytes. For example, the value
+   * "10KB" will be interpreted as 10240.
+   */
+  public void setMaxFileSize(String value) {
+    maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
+  }
+
+  protected void setQWForFiles(Writer writer) {
+    this.qw = new CountingQuietWriter(writer, errorHandler);
+  }
+
+  /**
+   * This method differentiates RollingFileAppender from its super class.
+   */
+  protected void subAppend(LoggingEvent event) {
+    super.subAppend(event);
+
+    if (fileName != null && qw != null) {
+      long size = ((CountingQuietWriter) qw).getCount();
+      if (size >= maxFileSize && size >= nextRollover) {
+        rollOver();
+      }
+    }
+  }
+
+  // Mangled file name. Append the current timestamp
+  private static String getLogFileName(String oldFileName) {
+    return oldFileName + "." + Long.toString(System.currentTimeMillis());
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sentry/blob/e62fa28d/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/HdfsTestUtil.java
----------------------------------------------------------------------
diff --git a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/HdfsTestUtil.java b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/HdfsTestUtil.java
index 859c793..e952a55 100644
--- a/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/HdfsTestUtil.java
+++ b/sentry-binding/sentry-binding-solr/src/test/java/org/apache/sentry/binding/solr/HdfsTestUtil.java
@@ -1,3 +1,17 @@
+/*
+ * 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;
 
 import java.io.File;
@@ -8,27 +22,8 @@ import java.util.Locale;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hdfs.MiniDFSCluster;
 
-/*
- * 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.
- */
-
-
 /**
- * Copied from Apache Solr since the solr-core test jar currently isn't
- * published
+ * Copied from Apache Solr since the solr-core test jar currently isn't published
  */
 public class HdfsTestUtil {
   private static Locale savedLocale;
@@ -50,8 +45,10 @@ public class HdfsTestUtil {
     conf.set("hdfs.minidfs.basedir", dir.getAbsolutePath() + File.separator + "hdfsBaseDir");
     conf.set("dfs.namenode.name.dir", dir.getAbsolutePath() + File.separator + "nameNodeNameDir");
 
-    System.setProperty("test.build.data", dir.getAbsolutePath() + File.separator + "hdfs" + File.separator + "build");
-    System.setProperty("test.cache.data", dir.getAbsolutePath() + File.separator + "hdfs" + File.separator + "cache");
+    System.setProperty("test.build.data",
+        dir.getAbsolutePath() + File.separator + "hdfs" + File.separator + "build");
+    System.setProperty("test.cache.data",
+        dir.getAbsolutePath() + File.separator + "hdfs" + File.separator + "cache");
     System.setProperty("solr.lock.type", "hdfs");
 
     MiniDFSCluster dfsCluster = new MiniDFSCluster(conf, dataNodes, true, null);
@@ -73,13 +70,10 @@ public class HdfsTestUtil {
     }
   }
 
-  public static String getDataDir(MiniDFSCluster dfsCluster, String dataDir)
-      throws IOException {
+  public static String getDataDir(MiniDFSCluster dfsCluster, String dataDir) throws IOException {
     URI uri = dfsCluster.getURI();
-    String dir = uri.toString()
-        + "/"
-        + new File(dataDir).toString().replaceAll(":", "_")
-            .replaceAll("/", "_");
+    String dir = uri.toString() + "/"
+        + new File(dataDir).toString().replaceAll(":", "_").replaceAll("/", "_");
     return dir;
   }
 }