Repository: incubator-sentry
Updated Branches:
  refs/heads/master 4796ec9b4 -> 60bb10037


http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/60bb1003/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentryIndexAuthorizationSingletonTest.java
----------------------------------------------------------------------
diff --git 
a/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentryIndexAuthorizationSingletonTest.java
 
b/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentryIndexAuthorizationSingletonTest.java
new file mode 100644
index 0000000..4bea251
--- /dev/null
+++ 
b/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentryIndexAuthorizationSingletonTest.java
@@ -0,0 +1,235 @@
+package org.apache.solr.sentry;
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.sentry.core.model.search.SearchModelAction;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.cloud.CloudDescriptor;
+import org.apache.solr.core.SolrCore;
+// import org.apache.solr.servlet.SolrHadoopAuthenticationFilter;
+import org.apache.solr.request.LocalSolrQueryRequest;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.request.SolrQueryRequestBase;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Test for SentryIndexAuthorizationSingleton
+ */
+public class SentryIndexAuthorizationSingletonTest extends SentryTestBase {
+
+  private static SolrCore core;
+  private static CloudDescriptor cloudDescriptor;
+  private static SentryIndexAuthorizationSingleton sentryInstance;
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    core = createCore("solrconfig.xml", "schema-minimal.xml");
+    // store the CloudDescriptor, because we will overwrite it with a mock
+    // and restore it later
+    cloudDescriptor = core.getCoreDescriptor().getCloudDescriptor();
+    sentryInstance = 
SentrySingletonTestInstance.getInstance().getSentryInstance();
+  }
+
+  @AfterClass
+  public static void afterClass() throws Exception {
+    closeCore(core, cloudDescriptor);
+    core = null;
+    cloudDescriptor = null;
+  }
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp(core);
+  }
+
+  /**
+   * Expect an unauthorized SolrException with a message that contains
+   * msgContains.
+   */
+  private void doExpectUnauthorized(SolrQueryRequest request,
+      Set<SearchModelAction> actions, String msgContains) throws Exception {
+    doExpectUnauthorized(sentryInstance, request, actions, msgContains);
+  }
+
+  private void doExpectUnauthorized(SentryIndexAuthorizationSingleton 
singleton, SolrQueryRequest request,
+      Set<SearchModelAction> actions, String msgContains) throws Exception {
+    try {
+      singleton.authorizeCollectionAction(request, actions);
+      Assert.fail("Expected SolrException");
+    } catch (SolrException ex) {
+      assertEquals(ex.code(), SolrException.ErrorCode.UNAUTHORIZED.code);
+      assertTrue(ex.getMessage().contains(msgContains));
+    }
+  }
+
+  @Test
+  public void testNoBinding() throws Exception {
+    // Use reflection to construct a non-singleton version of 
SentryIndexAuthorizationSingleton
+    // in order to get an instance without a binding
+    Constructor ctor =
+      
SentryIndexAuthorizationSingleton.class.getDeclaredConstructor(String.class);
+    ctor.setAccessible(true);
+    SentryIndexAuthorizationSingleton nonSingleton =
+      (SentryIndexAuthorizationSingleton)ctor.newInstance("");
+    doExpectUnauthorized(nonSingleton, null, null, "binding");
+
+    // test getUserName
+    try {
+      nonSingleton.getUserName(null);
+      Assert.fail("Expected Solr exception");
+    } catch (SolrException ex) {
+      assertEquals(ex.code(), SolrException.ErrorCode.UNAUTHORIZED.code);
+    }
+
+    Collection<String> groups = nonSingleton.getRoles("junit");
+    assertEquals(null, groups);
+  }
+
+  @Test
+  public void testNoHttpRequest() throws Exception {
+    SolrQueryRequest request = getRequest();
+    doExpectUnauthorized(request, null, "HttpServletRequest");
+  }
+
+ @Test
+  public void testNullUserName() throws Exception {
+    SolrQueryRequest request = getRequest();
+    prepareCollAndUser(core, request, "collection1", null);
+    doExpectUnauthorized(request, EnumSet.of(SearchModelAction.ALL),
+      "User null does not have privileges for collection1");
+  }
+
+  @Test
+  public void testEmptySuperUser() throws Exception {
+    System.setProperty("solr.authorization.superuser", "");
+    SolrQueryRequest request = getRequest();
+    prepareCollAndUser(core, request, "collection1", "solr");
+    doExpectUnauthorized(request, EnumSet.of(SearchModelAction.ALL),
+      "User solr does not have privileges for collection1");
+  }
+
+  /**
+   * User name matches super user, should have access otherwise
+   */
+  @Test
+  public void testSuperUserAccess() throws Exception {
+    System.setProperty("solr.authorization.superuser", "junit");
+    SolrQueryRequest request = getRequest();
+    prepareCollAndUser(core, request, "collection1", "junit");
+
+    sentryInstance.authorizeCollectionAction(
+      request, EnumSet.of(SearchModelAction.ALL));
+  }
+
+  /**
+   * User name matches super user, should not have access otherwise
+   */
+  @Test
+  public void testSuperUserNoAccess() throws Exception {
+    System.setProperty("solr.authorization.superuser", "junit");
+    SolrQueryRequest request = getRequest();
+    prepareCollAndUser(core, request, "bogusCollection", "junit");
+
+    sentryInstance.authorizeCollectionAction(
+      request, EnumSet.of(SearchModelAction.ALL));
+  }
+
+  /**
+   * Test getting the user name.
+   */
+  @Test
+  public void testUserName() throws Exception {
+    SolrQueryRequest request = null;
+    try {
+      // no http request
+      request = new SolrQueryRequestBase( core, new ModifiableSolrParams() ) 
{};
+      try {
+        sentryInstance.getUserName(request);
+        Assert.fail("Expected SolrException");
+      } catch (SolrException ex) {
+        assertEquals(ex.code(), SolrException.ErrorCode.UNAUTHORIZED.code);
+      }
+
+      // no http request, but LocalSolrQueryRequest
+      LocalSolrQueryRequest localRequest = null;
+      try {
+        localRequest = new LocalSolrQueryRequest(null, new 
ModifiableSolrParams());
+        String superUser = (System.getProperty("solr.authorization.superuser", 
"solr"));
+        String localName = sentryInstance.getUserName(localRequest);
+        assertEquals(superUser, localName);
+      } finally {
+        if (localRequest != null) localRequest.close();
+      }
+
+      // null userName
+      SolrQueryRequest sqr = getRequest();
+      prepareCollAndUser(core, sqr, "collection", null, true);
+      String nullName = sentryInstance.getUserName(sqr);
+      assertEquals(null, nullName);
+
+      // standard userName
+      String userName = "foobar";
+      prepareCollAndUser(core, sqr, "collection", userName, true);
+      String returnedName = sentryInstance.getUserName(sqr);
+      assertEquals(userName, returnedName);
+    } finally {
+      if (request != null) request.close();
+    }
+  }
+
+  /**
+   * Test getting the roles from user name
+   */
+  @Test
+  public void testGetRoles() throws Exception {
+    Collection<String> emptyCollection = ImmutableSet.<String>of();
+
+    // null user
+    Collection<String> roles = sentryInstance.getRoles(null);
+    assertTrue(CollectionUtils.isEqualCollection(emptyCollection, roles));
+
+    // no group
+    roles = sentryInstance.getRoles("bogusUser");
+    assertTrue(CollectionUtils.isEqualCollection(emptyCollection, roles));
+
+    // no role
+    roles = sentryInstance.getRoles("undefinedRoleUser");
+    assertTrue(CollectionUtils.isEqualCollection(emptyCollection, roles));
+
+    // single member
+    Collection<String> singleRole = ImmutableSet.<String>of("junit_role");
+    roles = sentryInstance.getRoles("junit");
+    assertTrue(CollectionUtils.isEqualCollection(singleRole, roles));
+
+    // multiple members
+    Collection<String> multipleRoles = ImmutableSet.<String>of("junit_role", 
"queryOnlyAdmin_role", "updateOnlyAdmin_role");
+    roles = sentryInstance.getRoles("multiGroupUser");
+    assertTrue(CollectionUtils.isEqualCollection(multipleRoles, roles));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/60bb1003/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentrySingletonTestInstance.java
----------------------------------------------------------------------
diff --git 
a/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentrySingletonTestInstance.java
 
b/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentrySingletonTestInstance.java
new file mode 100644
index 0000000..ae02466
--- /dev/null
+++ 
b/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentrySingletonTestInstance.java
@@ -0,0 +1,94 @@
+/*
+ * 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.lang.reflect.Constructor;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.handler.SecureRequestHandlerUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.commons.codec.Charsets;
+
+/**
+ * Provides SentryIndexAuthorizationSingleton instance for use with
+ * sentry-related unit tests.  In the unit tests, the primary
+ * SentryIndexAuthorizationSingleton will be initialized without a sentry-site,
+ * thus Sentry checking will not occur.  The SentryIndexAuthorizationSingleton
+ * provided by getInstance in this class will be properly initialized for 
Sentry checking.
+ *
+ * NOTE: this is a hack, as there are multiple "singletons".  It may be cleaner
+ * to just force the Sentry related tests to run in their own JVMs, so they
+ * will always have the properly-initialized SentryIndexAuthorizationSingleton.
+ */
+public class SentrySingletonTestInstance {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(SentrySingletonTestInstance.class);
+
+  private static SentrySingletonTestInstance INSTANCE = new 
SentrySingletonTestInstance();
+  private SentryIndexAuthorizationSingleton sentryInstance;
+  private File sentrySite;
+
+  private void addPropertyToSentry(StringBuilder builder, String name, String 
value) {
+    builder.append("<property>\n");
+    builder.append("<name>").append(name).append("</name>\n");
+    builder.append("<value>").append(value).append("</value>\n");
+    builder.append("</property>\n");
+  }
+
+  public void setupSentry() throws Exception {
+    sentrySite = File.createTempFile("sentry-site", "xml");
+    File authProviderDir = SolrTestCaseJ4.getFile("sentry-handlers/sentry");
+    sentrySite.deleteOnExit();
+
+    // need to write sentry-site at execution time because we don't know
+    // the location of sentry.solr.provider.resource beforehand
+    StringBuilder sentrySiteData = new StringBuilder();
+    sentrySiteData.append("<configuration>\n");
+    addPropertyToSentry(sentrySiteData, "sentry.provider",
+      
"org.apache.sentry.provider.file.LocalGroupResourceAuthorizationProvider");
+    addPropertyToSentry(sentrySiteData, "sentry.solr.provider.resource",
+       new File(authProviderDir.toString(), 
"test-authz-provider.ini").toURI().toURL().toString());
+    sentrySiteData.append("</configuration>\n");
+    FileUtils.writeStringToFile(sentrySite,sentrySiteData.toString(), 
Charsets.UTF_8.toString());
+  }
+
+  private SentrySingletonTestInstance() {
+    try {
+      setupSentry();
+      Constructor ctor =
+        
SentryIndexAuthorizationSingleton.class.getDeclaredConstructor(String.class);
+      ctor.setAccessible(true);
+      sentryInstance =
+        
(SentryIndexAuthorizationSingleton)ctor.newInstance(sentrySite.toURI().toURL().toString().substring("file:".length()));
+      // ensure all SecureAdminHandlers use this instance
+      SecureRequestHandlerUtil.testOverride = sentryInstance;
+    } catch (Exception ex) {
+      LOGGER.error("Unable to create SentrySingletonTestInstance", ex);
+    }
+  }
+
+  public static SentrySingletonTestInstance getInstance() {
+    return INSTANCE;
+  }
+
+  public SentryIndexAuthorizationSingleton getSentryInstance() {
+    return sentryInstance;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/60bb1003/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentryTestBase.java
----------------------------------------------------------------------
diff --git 
a/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentryTestBase.java
 
b/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentryTestBase.java
new file mode 100644
index 0000000..b5548e6
--- /dev/null
+++ 
b/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/sentry/SentryTestBase.java
@@ -0,0 +1,179 @@
+package org.apache.solr.sentry;
+/*
+ * 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.
+ */
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.cloud.CloudDescriptor;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.core.CoreDescriptor;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.request.SolrQueryRequestBase;
+import org.apache.solr.request.SolrRequestHandler;
+import org.apache.solr.response.SolrQueryResponse;
+import org.easymock.EasyMock;
+import org.easymock.IExpectationSetters;
+
+import java.lang.reflect.Field;
+
+import org.junit.Assert;
+
+/**
+ * Base class for Sentry tests
+ */
+public abstract class SentryTestBase extends SolrTestCaseJ4 {
+
+  private static final String USER_NAME = "solr.user.name";
+
+  private SolrQueryRequest request;
+
+  public void setUp(SolrCore core) throws Exception {
+    super.setUp();
+    request = new SolrQueryRequestBase( core, new ModifiableSolrParams() ) { };
+  }
+
+  @Override
+  public void tearDown() throws Exception {
+    super.tearDown();
+    request.close();
+  }
+
+  public static SolrCore createCore(String solrconfig, String schema) throws 
Exception {
+    initCore(solrconfig, schema, "sentry-handlers/solr");
+    return h.getCoreContainer().getCore("collection1");
+  }
+
+  public static void closeCore(SolrCore coreToClose, CloudDescriptor 
cloudDescriptor)
+      throws Exception {
+    if (cloudDescriptor != null) {
+      CoreDescriptor coreDescriptor = coreToClose.getCoreDescriptor();
+      Field cloudDescField = 
CoreDescriptor.class.getDeclaredField("cloudDesc");
+      cloudDescField.setAccessible(true);
+      cloudDescField.set(coreDescriptor, cloudDescriptor);
+    }
+    coreToClose.close();
+  }
+
+  protected SolrQueryRequest getRequest() {
+    return request;
+  }
+
+  protected SolrQueryRequest prepareCollAndUser(SolrCore core, 
SolrQueryRequest request,
+      String collection, String user) throws Exception {
+    return prepareCollAndUser(core, request, collection, user, true);
+  }
+
+  protected SolrQueryRequest prepareCollAndUser(SolrCore core, 
SolrQueryRequest request,
+      String collection, String user, boolean onlyOnce) throws Exception {
+    CloudDescriptor mCloudDescriptor = 
EasyMock.createMock(CloudDescriptor.class);
+    IExpectationSetters getCollNameExpect = 
EasyMock.expect(mCloudDescriptor.getCollectionName()).andReturn(collection);
+    getCollNameExpect.anyTimes();
+    IExpectationSetters getShardIdExpect = 
EasyMock.expect(mCloudDescriptor.getShardId()).andReturn("shard1");
+    getShardIdExpect.anyTimes();
+    EasyMock.replay(mCloudDescriptor);
+    CoreDescriptor coreDescriptor = core.getCoreDescriptor();
+    Field cloudDescField = CoreDescriptor.class.getDeclaredField("cloudDesc");
+    cloudDescField.setAccessible(true);
+    cloudDescField.set(coreDescriptor, mCloudDescriptor);
+
+    HttpServletRequest httpServletRequest = 
EasyMock.createMock(HttpServletRequest.class);
+    IExpectationSetters getAttributeExpect =
+        
EasyMock.expect(httpServletRequest.getAttribute(USER_NAME)).andReturn(user);
+    if(!onlyOnce) getAttributeExpect.anyTimes();
+    EasyMock.replay(httpServletRequest);
+    request.getContext().put("httpRequest", httpServletRequest);
+    return request;
+  }
+
+  private void verifyAuthorized(SolrRequestHandler handler,
+      RequestHandlerBase handlerBase, SolrQueryRequest req) throws Exception {
+    assert((handler == null && handlerBase != null)
+        || (handler != null && handlerBase == null));
+    SolrQueryResponse rsp = new SolrQueryResponse();
+    // just ensure we don't get an unauthorized exception
+    try {
+      if (handler != null) {
+        handler.handleRequest(req, rsp);
+      } else {
+        handlerBase.handleRequestBody(req, rsp);
+      }
+    } catch (SolrException ex) {
+      assertFalse(ex.code() == SolrException.ErrorCode.UNAUTHORIZED.code);
+    } catch (Exception ex) {
+      // okay, we only want to verify we didn't get an Unauthorized exception,
+      // going to treat each handler as a black box.
+    }
+  }
+
+  protected void verifyAuthorized(RequestHandlerBase handlerBase,
+      SolrQueryRequest req) throws Exception {
+    verifyAuthorized(null, handlerBase, req);
+  }
+
+
+  protected void verifyAuthorized(SolrRequestHandler handler,
+      SolrQueryRequest req) throws Exception {
+    verifyAuthorized(handler, null, req);
+  }
+
+  protected void verifyUnauthorized(SolrRequestHandler handler,
+      RequestHandlerBase handlerBase, SolrQueryRequest req, String collection, 
String user, boolean shouldFailAdmin)
+          throws Exception {
+    assert((handler == null && handlerBase != null)
+        || (handler != null && handlerBase == null));
+    String exMsgContains = "User " + user + " does not have privileges for " + 
(shouldFailAdmin?"admin":collection);
+    SolrQueryResponse rsp = new SolrQueryResponse();
+    try {
+      if (handler!= null) {
+        handler.handleRequest(req, rsp);
+        if (rsp.getException() != null) {
+          throw rsp.getException();
+        }
+      } else {
+        handlerBase.handleRequestBody(req, rsp);
+        if (rsp.getException() != null) {
+          throw rsp.getException();
+        }
+      }
+      Assert.fail("Expected SolrException");
+    } catch (SolrException ex) {
+      assertEquals(SolrException.ErrorCode.UNAUTHORIZED.code, ex.code());
+      assertTrue(ex.getMessage().contains(exMsgContains));
+    } catch (Exception ex) {
+      Assert.fail("Expected SolrException");
+    }
+  }
+
+  protected void verifyUnauthorized(RequestHandlerBase handlerBase,
+      SolrQueryRequest req, String collection, String user, boolean 
shouldFailAdmin) throws Exception {
+    verifyUnauthorized(null, handlerBase, req, collection, user, 
shouldFailAdmin);
+  }
+
+  protected void verifyUnauthorized(RequestHandlerBase handlerBase,
+      SolrQueryRequest req, String collection, String user) throws Exception {
+    verifyUnauthorized(null, handlerBase, req, collection, user, false);
+  }
+
+  protected void verifyUnauthorized(SolrRequestHandler handler,
+      SolrQueryRequest req, String collection, String user) throws Exception {
+    verifyUnauthorized(handler, null, req, collection, user, false);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/60bb1003/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/update/processor/UpdateIndexAuthorizationProcessorTest.java
----------------------------------------------------------------------
diff --git 
a/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/update/processor/UpdateIndexAuthorizationProcessorTest.java
 
b/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/update/processor/UpdateIndexAuthorizationProcessorTest.java
new file mode 100644
index 0000000..e297232
--- /dev/null
+++ 
b/sentry-solr/solr-sentry-handlers/src/test/java/org/apache/solr/update/processor/UpdateIndexAuthorizationProcessorTest.java
@@ -0,0 +1,181 @@
+package org.apache.solr.update.processor;
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.List;
+import java.util.TreeSet;
+
+import org.apache.commons.lang.mutable.MutableInt;
+import org.apache.solr.cloud.CloudDescriptor;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.sentry.SentryTestBase;
+import org.apache.solr.sentry.SentrySingletonTestInstance;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test for UpdateIndexAuthorizationProcessor
+ */
+public class UpdateIndexAuthorizationProcessorTest extends SentryTestBase {
+
+  private List<String> methodNames = Arrays.asList("processAdd", 
"processDelete",
+    "processMergeIndexes","processCommit", "processRollback", "finish");
+
+  private static SolrCore core;
+  private static CloudDescriptor cloudDescriptor;
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    core = createCore("solrconfig.xml", "schema-minimal.xml");
+    // store the CloudDescriptor, because we will overwrite it with a mock
+    // and restore it later
+    cloudDescriptor = core.getCoreDescriptor().getCloudDescriptor();
+  }
+
+  @AfterClass
+  public static void afterClass() throws Exception {
+    closeCore(core, cloudDescriptor);
+    core = null;
+    cloudDescriptor = null;
+  }
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp(core);
+  }
+
+  private void verifyAuthorized(String collection, String user) throws 
Exception {
+    getProcessor(collection, user).processAdd(null);
+    getProcessor(collection, user).processDelete(null);
+    getProcessor(collection, user).processMergeIndexes(null);
+    getProcessor(collection, user).processCommit(null);
+    getProcessor(collection, user).processRollback(null);
+    getProcessor(collection, user).finish();
+  }
+
+  private void verifyUnauthorizedException(SolrException ex, String 
exMsgContains, MutableInt numExceptions) {
+    assertEquals(ex.code(), SolrException.ErrorCode.UNAUTHORIZED.code);
+    assertTrue(ex.getMessage().contains(exMsgContains));
+    numExceptions.add(1);
+  }
+
+  private void verifyUnauthorized(String collection, String user) throws 
Exception {
+    MutableInt numExceptions = new MutableInt(0);
+    String contains = "User " + user + " does not have privileges for " + 
collection;
+
+    try {
+      getProcessor(collection, user).processAdd(null);
+    } catch(SolrException ex) {
+      verifyUnauthorizedException(ex, contains, numExceptions);
+    }
+    try {
+      getProcessor(collection, user).processDelete(null);
+    } catch(SolrException ex) {
+      verifyUnauthorizedException(ex, contains, numExceptions);
+    }
+    try {
+      getProcessor(collection, user).processMergeIndexes(null);
+    } catch(SolrException ex) {
+      verifyUnauthorizedException(ex, contains, numExceptions);
+    }
+    try {
+      getProcessor(collection, user).processCommit(null);
+    } catch(SolrException ex) {
+      verifyUnauthorizedException(ex, contains, numExceptions);
+    }
+    try {
+      getProcessor(collection, user).processRollback(null);
+    } catch(SolrException ex) {
+      verifyUnauthorizedException(ex, contains, numExceptions);
+    }
+    try {
+      getProcessor(collection, user).finish();
+    } catch(SolrException ex) {
+      verifyUnauthorizedException(ex, contains, numExceptions);
+    }
+
+    assertEquals(methodNames.size(), numExceptions.intValue());
+  }
+
+  private UpdateIndexAuthorizationProcessor getProcessor(String collection, 
String user)
+      throws Exception {
+    SolrQueryRequest request = getRequest();
+    prepareCollAndUser(core, request, collection, user);
+    return new UpdateIndexAuthorizationProcessor(
+      SentrySingletonTestInstance.getInstance().getSentryInstance(), request, 
null, null);
+  }
+
+ /**
+  * Test the UpdateIndexAuthorizationComponent on a collection that
+  * the user has ALL access
+  */
+  @Test
+  public void testUpdateComponentAccessAll() throws Exception {
+    verifyAuthorized("collection1", "junit");
+  }
+
+ /**
+  * Test the UpdateIndexAuthorizationComponent on a collection that
+  * the user has UPDATE only access
+  */
+  @Test
+  public void testUpdateComponentAccessUpdate() throws Exception {
+    verifyAuthorized("updateCollection", "junit");
+  }
+
+ /**
+  * Test the UpdateIndexAuthorizationComponent on a collection that
+  * the user has QUERY only access
+  */
+  @Test
+  public void testUpdateComponentAccessQuery() throws Exception {
+    verifyUnauthorized("queryCollection", "junit");
+  }
+
+ /**
+  * Test the UpdateIndexAuthorizationComponent on a collection that
+  * the user has no access
+  */
+  @Test
+  public void testUpdateComponentAccessNone() throws Exception {
+    verifyUnauthorized("noAccessCollection", "junit");
+  }
+
+  /**
+   * Ensure no new methods have been added to base class that are not invoking
+   * Sentry
+   */
+  @Test
+  public void testAllMethodsChecked() throws Exception {
+    Method [] methods = UpdateRequestProcessor.class.getDeclaredMethods();
+    TreeSet<String> foundNames = new TreeSet<String>();
+    for (Method method : methods) {
+      if (Modifier.isPublic(method.getModifiers())) {
+        foundNames.add(method.getName());
+      }
+    }
+    assertEquals(methodNames.size(), foundNames.size());
+    assertTrue(foundNames.containsAll(methodNames));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/60bb1003/sentry-tests/sentry-tests-solr/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-solr/pom.xml 
b/sentry-tests/sentry-tests-solr/pom.xml
index d40dbd2..dfc3792 100644
--- a/sentry-tests/sentry-tests-solr/pom.xml
+++ b/sentry-tests/sentry-tests-solr/pom.xml
@@ -40,7 +40,7 @@ limitations under the License.
       <artifactId>solr-test-framework</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.solr</groupId>
+      <groupId>org.apache.sentry</groupId>
       <artifactId>solr-sentry-handlers</artifactId>
     </dependency>
     <dependency>

Reply via email to