Repository: incubator-sentry
Updated Branches:
  refs/heads/master 3226ce992 -> 7d214749a


SENTRY-223: Add a test for updates with doc-level security (Gregory Chanan via 
Vamsee Yarlagadda)


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

Branch: refs/heads/master
Commit: 7d214749a349567f258e3f83c554ae73cd5c0781
Parents: 3226ce9
Author: Vamsee <[email protected]>
Authored: Wed May 21 18:21:20 2014 -0700
Committer: Vamsee <[email protected]>
Committed: Wed May 21 18:21:20 2014 -0700

----------------------------------------------------------------------
 .../tests/e2e/solr/TestDocLevelOperations.java  | 291 ++++++++++++++-----
 .../solr/sentry/test-authz-provider.ini         |   6 +-
 2 files changed, 220 insertions(+), 77 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/7d214749/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestDocLevelOperations.java
----------------------------------------------------------------------
diff --git 
a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestDocLevelOperations.java
 
b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestDocLevelOperations.java
index d4307ec..31ecd5b 100644
--- 
a/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestDocLevelOperations.java
+++ 
b/sentry-tests/sentry-tests-solr/src/test/java/org/apache/sentry/tests/e2e/solr/TestDocLevelOperations.java
@@ -18,7 +18,6 @@ package org.apache.sentry.tests.e2e.solr;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import org.junit.After;
 import org.junit.Before;
 import static org.junit.Assert.assertEquals;
@@ -27,6 +26,8 @@ import static org.junit.Assert.assertTrue;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.client.solrj.impl.CloudSolrServer;
 import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.client.solrj.response.UpdateResponse;
+
 import org.apache.solr.common.SolrDocument;
 import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.SolrInputDocument;
@@ -34,6 +35,7 @@ import org.apache.solr.common.SolrInputDocument;
 import java.io.File;
 import java.net.URLEncoder;
 import java.util.ArrayList;
+import java.util.List;
 
 import org.junit.Test;
 
@@ -70,12 +72,18 @@ public class TestDocLevelOperations extends 
AbstractSolrSentryTestBase {
   }
 
   /**
-   * Test that queries from different users only return the documents they 
have access to.
+   * Creates docs as follows and verifies queries work as expected:
+   * - creates NUM_DOCS documents, where the document id equals the order
+   *   it was created in, starting at 0
+   * - even-numbered documents get "junit_role" auth token
+   * - odd-numbered documents get "admin_role" auth token
+   * - all documents get some bogus auth tokens
+   * - all documents get a docLevel_role auth token
    */
-  @Test
-  public void testDocLevelOperations() throws Exception {
-    String collectionName = "docLevelCollection";
-    setupCollectionWithDocSecurity(collectionName);
+  private void createDocsAndQuerySimple(String collectionName) throws 
Exception {
+
+    // ensure no current documents
+    verifyDeletedocsPass(ADMIN_USER, collectionName, true);
 
     // create documents
     ArrayList<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
@@ -134,106 +142,241 @@ public class TestDocLevelOperations extends 
AbstractSolrSentryTestBase {
       setAuthenticationUser("docLevel");
       rsp = server.query(query);
       assertEquals(NUM_DOCS, rsp.getResults().getNumFound());
-
-      // test filter queries work as AND -- i.e. user can't avoid doc-level
-      // checks by prefixing their own filterQuery
-      setAuthenticationUser("junit");
-      String fq = URLEncoder.encode(" {!raw f=" + AUTH_FIELD + " 
v=docLevel_role}");
-      String path = "/" + collectionName + "/select?q=*:*&fq="+fq;
-      String retValue = makeHttpRequest(server, "GET", path, null, null);
-      assertTrue(retValue.contains("numFound=\"" + NUM_DOCS / 2 + "\" "));
-
-      // test that user can't inject an "OR" into the query
-      final String syntaxErrorMsg = "org.apache.solr.search.SyntaxError: 
Cannot parse";
-      fq = URLEncoder.encode(" {!raw f=" + AUTH_FIELD + " v=docLevel_role} OR 
");
-      path = "/" + collectionName + "/select?q=*:*&fq="+fq;
-      retValue = makeHttpRequest(server, "GET", path, null, null);
-      assertTrue(retValue.contains(syntaxErrorMsg));
-
-      // same test, prefix OR this time
-      fq = URLEncoder.encode(" OR {!raw f=" + AUTH_FIELD + " 
v=docLevel_role}");
-      path = "/" + collectionName + "/select?q=*:*&fq="+fq;
-      retValue = makeHttpRequest(server, "GET", path, null, null);
-      assertTrue(retValue.contains(syntaxErrorMsg));
     } finally {
       server.shutdown();
     }
   }
 
   /**
+   * Test that queries from different users only return the documents they 
have access to.
+   */
+  @Test
+  public void testDocLevelOperations() throws Exception {
+    String collectionName = "docLevelCollection";
+    setupCollectionWithDocSecurity(collectionName);
+
+    try {
+      createDocsAndQuerySimple(collectionName);
+      CloudSolrServer server = getCloudSolrServer(collectionName);
+      try {
+        // test filter queries work as AND -- i.e. user can't avoid doc-level
+        // checks by prefixing their own filterQuery
+        setAuthenticationUser("junit");
+        String fq = URLEncoder.encode(" {!raw f=" + AUTH_FIELD + " 
v=docLevel_role}");
+        String path = "/" + collectionName + "/select?q=*:*&fq="+fq;
+        String retValue = makeHttpRequest(server, "GET", path, null, null);
+        assertTrue(retValue.contains("numFound=\"" + NUM_DOCS / 2 + "\" "));
+
+        // test that user can't inject an "OR" into the query
+        final String syntaxErrorMsg = "org.apache.solr.search.SyntaxError: 
Cannot parse";
+        fq = URLEncoder.encode(" {!raw f=" + AUTH_FIELD + " v=docLevel_role} 
OR ");
+        path = "/" + collectionName + "/select?q=*:*&fq="+fq;
+        retValue = makeHttpRequest(server, "GET", path, null, null);
+        assertTrue(retValue.contains(syntaxErrorMsg));
+
+        // same test, prefix OR this time
+        fq = URLEncoder.encode(" OR {!raw f=" + AUTH_FIELD + " 
v=docLevel_role}");
+        path = "/" + collectionName + "/select?q=*:*&fq="+fq;
+        retValue = makeHttpRequest(server, "GET", path, null, null);
+        assertTrue(retValue.contains(syntaxErrorMsg));
+      } finally {
+        server.shutdown();
+      }
+    } finally {
+      deleteCollection(collectionName);
+    }
+  }
+
+  /**
    * Test the allRolesToken.  Make it a keyword in the query language ("OR")
    * to make sure it is treated literally rather than interpreted.
    */
   @Test
   public void testAllRolesToken() throws Exception {
-    String allRolesToken = "OR";
     String collectionName = "allRolesCollection";
     setupCollectionWithDocSecurity(collectionName);
 
-    int junitFactor = 2;
-    int allRolesFactor  = 5;
 
-    int totalJunitAdded = 0; // total docs added with junit token
-    int totalAllRolesAdded = 0; // total number of docs with the allRolesToken
-    int totalOnlyAllRolesAdded = 0; // total number of docs with _only_ the 
allRolesToken
+    try {
+      String allRolesToken = "OR";
+      int junitFactor = 2;
+      int allRolesFactor  = 5;
 
-    // create documents
-    ArrayList<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
-    for (int i = 0; i < NUM_DOCS; ++i) {
-      boolean addedViaJunit = false;
-      SolrInputDocument doc = new SolrInputDocument();
-      String iStr = Long.toString(i);
-      doc.addField("id", iStr);
-      doc.addField("description", "description" + iStr);
+      int totalJunitAdded = 0; // total docs added with junit token
+      int totalAllRolesAdded = 0; // total number of docs with the 
allRolesToken
+      int totalOnlyAllRolesAdded = 0; // total number of docs with _only_ the 
allRolesToken
 
-      if (i % junitFactor == 0) {
-        doc.addField(AUTH_FIELD, "junit_role");
-        addedViaJunit = true;
-        ++totalJunitAdded;
-      } if (i % allRolesFactor == 0) {
-        doc.addField(AUTH_FIELD, allRolesToken);
-        ++totalAllRolesAdded;
-        if (!addedViaJunit) ++totalOnlyAllRolesAdded;
+      // create documents
+      ArrayList<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
+      for (int i = 0; i < NUM_DOCS; ++i) {
+        boolean addedViaJunit = false;
+        SolrInputDocument doc = new SolrInputDocument();
+        String iStr = Long.toString(i);
+        doc.addField("id", iStr);
+        doc.addField("description", "description" + iStr);
+
+        if (i % junitFactor == 0) {
+          doc.addField(AUTH_FIELD, "junit_role");
+          addedViaJunit = true;
+          ++totalJunitAdded;
+        } if (i % allRolesFactor == 0) {
+          doc.addField(AUTH_FIELD, allRolesToken);
+          ++totalAllRolesAdded;
+          if (!addedViaJunit) ++totalOnlyAllRolesAdded;
+        }
+        docs.add(doc);
       }
-      docs.add(doc);
+      // make sure our factors give us interesting results --
+      // that some docs only have all roles and some only have junit
+      assert(totalOnlyAllRolesAdded > 0);
+      assert(totalJunitAdded > totalAllRolesAdded);
+
+      CloudSolrServer server = getCloudSolrServer(collectionName);
+      try {
+        server.add(docs);
+        server.commit(true, true);
+
+        // queries
+        SolrQuery query = new SolrQuery();
+        query.setQuery("*:*");
+
+        // as admin  -- should only get all roles token documents
+        setAuthenticationUser("admin");
+        QueryResponse rsp = server.query(query);
+        SolrDocumentList docList = rsp.getResults();
+        assertEquals(totalAllRolesAdded, docList.getNumFound());
+        for (SolrDocument doc : docList) {
+          String id = doc.getFieldValue("id").toString();
+          assertEquals(0, Long.valueOf(id) % allRolesFactor);
+        }
+
+        // as junit -- should get junit added + onlyAllRolesAdded
+        setAuthenticationUser("junit");
+        rsp = server.query(query);
+        docList = rsp.getResults();
+        assertEquals(totalJunitAdded + totalOnlyAllRolesAdded, 
docList.getNumFound());
+        for (SolrDocument doc : docList) {
+          String id = doc.getFieldValue("id").toString();
+          boolean addedJunit = (Long.valueOf(id) % junitFactor) == 0;
+          boolean onlyAllRoles = !addedJunit && (Long.valueOf(id) % 
allRolesFactor) == 0;
+          assertEquals(true, addedJunit || onlyAllRoles);
+        }
+      } finally {
+        server.shutdown();
+      }
+    } finally {
+      deleteCollection(collectionName);
     }
-    // make sure our factors give us interesting results --
-    // that some docs only have all roles and some only have junit
-    assert(totalOnlyAllRolesAdded > 0);
-    assert(totalJunitAdded > totalAllRolesAdded);
+  }
 
+  /**
+   * delete the docs as "deleteUser" using deleteByQuery "deleteQueryStr".
+   * Verify that number of docs returned for "queryUser" equals
+   * "expectedQueryDocs" after deletion.
+   */
+  private void deleteByQueryTest(String collectionName, String deleteUser,
+      String deleteByQueryStr, String queryUser, int expectedQueryDocs) throws 
Exception {
+    createDocsAndQuerySimple(collectionName);
     CloudSolrServer server = getCloudSolrServer(collectionName);
     try {
-      server.add(docs);
-      server.commit(true, true);
+      SolrQuery query = new SolrQuery();
+      query.setQuery("*:*");
 
-      // queries
+      setAuthenticationUser(deleteUser);
+      server.deleteByQuery(deleteByQueryStr);
+      server.commit();
+      QueryResponse rsp =  server.query(query);
+      long junitResults = rsp.getResults().getNumFound();
+      assertEquals(0, junitResults);
+
+      setAuthenticationUser(queryUser);
+      rsp =  server.query(query);
+      long docLevelResults = rsp.getResults().getNumFound();
+      assertEquals(expectedQueryDocs, docLevelResults);
+    } finally {
+      server.shutdown();
+    }
+  }
+
+  private void deleteByIdTest(String collectionName) throws Exception {
+    createDocsAndQuerySimple(collectionName);
+    CloudSolrServer server = getCloudSolrServer(collectionName);
+    try {
       SolrQuery query = new SolrQuery();
       query.setQuery("*:*");
 
-      // as admin  -- should only get all roles token documents
-      setAuthenticationUser("admin");
-      QueryResponse rsp = server.query(query);
-      SolrDocumentList docList = rsp.getResults();
-      assertEquals(totalAllRolesAdded, docList.getNumFound());
-      for (SolrDocument doc : docList) {
-        String id = doc.getFieldValue("id").toString();
-        assertEquals(0, Long.valueOf(id) % allRolesFactor);
+      setAuthenticationUser("junit");
+      List<String> allIds = new ArrayList<String>(NUM_DOCS);
+      for (int i = 0; i < NUM_DOCS; ++i) {
+        allIds.add(Long.toString(i));
       }
+      server.deleteById(allIds);
+      server.commit();
+
+      QueryResponse rsp =  server.query(query);
+      long junitResults = rsp.getResults().getNumFound();
+      assertEquals(0, junitResults);
+
+      setAuthenticationUser("docLevel");
+      rsp =  server.query(query);
+      long docLevelResults = rsp.getResults().getNumFound();
+      assertEquals(0, docLevelResults);
+    } finally {
+      server.shutdown();
+    }
+  }
 
-      // as junit -- should get junit added + onlyAllRolesAdded
+  private void updateDocsTest(String collectionName) throws Exception {
+    createDocsAndQuerySimple(collectionName);
+    CloudSolrServer server = getCloudSolrServer(collectionName);
+    try {
       setAuthenticationUser("junit");
+      String docIdStr = Long.toString(1);
+
+      // verify we can't view one of the odd documents
+      SolrQuery query = new SolrQuery();
+      query.setQuery("id:"+docIdStr);
+      QueryResponse rsp = server.query(query);
+      assertEquals(0, rsp.getResults().getNumFound());
+
+      // overwrite the document that we can't see
+      ArrayList<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
+      SolrInputDocument doc = new SolrInputDocument();
+      doc.addField("id", docIdStr);
+      doc.addField("description", "description" + docIdStr);
+      doc.addField(AUTH_FIELD, "junit_role");
+      docs.add(doc);
+      server.add(docs);
+      server.commit();
+
+      // verify we can now view the document
       rsp = server.query(query);
-      docList = rsp.getResults();
-      assertEquals(totalJunitAdded + totalOnlyAllRolesAdded, 
docList.getNumFound());
-      for (SolrDocument doc : docList) {
-        String id = doc.getFieldValue("id").toString();
-        boolean addedJunit = (Long.valueOf(id) % junitFactor) == 0;
-        boolean onlyAllRoles = !addedJunit && (Long.valueOf(id) % 
allRolesFactor) == 0;
-        assertEquals(true, addedJunit || onlyAllRoles);
-      }
+      assertEquals(1, rsp.getResults().getNumFound());
     } finally {
       server.shutdown();
     }
   }
+
+  @Test
+  public void testUpdateDeleteOperations() throws Exception {
+    String collectionName = "testUpdateDeleteOperations";
+
+    setupCollectionWithDocSecurity(collectionName);
+    try {
+      createDocsAndQuerySimple(collectionName);
+
+      // test deleteByQuery "*:*"
+      deleteByQueryTest(collectionName, "junit", "*:*", "docLevel", 0);
+
+      // test deleteByQuery non-*:*
+      deleteByQueryTest(collectionName, "junit", "sentry_auth:docLevel_role", 
"docLevel", 0);
+
+      // test deleting all documents by Id
+      deleteByIdTest(collectionName);
+
+      updateDocsTest(collectionName);
+    } finally {
+      deleteCollection(collectionName);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/7d214749/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini
----------------------------------------------------------------------
diff --git 
a/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini
 
b/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini
index b7aa0c8..96ab0d4 100644
--- 
a/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini
+++ 
b/sentry-tests/sentry-tests-solr/src/test/resources/solr/sentry/test-authz-provider.ini
@@ -29,9 +29,9 @@ admin_query_update_group = admin_query_update_role
 admin_all_group = admin_all_role
 
 [roles]
-junit_role = collection=admin, collection=collection1, 
collection=docLevelCollection, collection=allRolesCollection
-docLevel_role = collection=docLevelCollection
-admin_role = collection=admin, collection=collection1, 
collection=sentryCollection, collection=sentryCollection_underlying1, 
collection=sentryCollection_underlying2, collection=docLevelCollection, 
collection=allRolesCollection, collection=testInvariantCollection
+junit_role = collection=admin, collection=collection1, 
collection=docLevelCollection, collection=allRolesCollection, 
collection=testUpdateDeleteOperations
+docLevel_role = collection=docLevelCollection, 
collection=testUpdateDeleteOperations
+admin_role = collection=admin, collection=collection1, 
collection=sentryCollection, collection=sentryCollection_underlying1, 
collection=sentryCollection_underlying2, collection=docLevelCollection, 
collection=allRolesCollection, collection=testInvariantCollection, 
collection=testUpdateDeleteOperations
 sentryCollection_query_role = collection=sentryCollection->action=query
 sentryCollection_update_role = collection=sentryCollection->action=update
 sentryCollection_query_update_role = 
collection=sentryCollection->action=query, 
collection=sentryCollection->action=update

Reply via email to