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;
}
}