Revamp fix for CONNECTORS-886.

git-svn-id: https://svn.apache.org/repos/asf/manifoldcf/integration/solr-4.x/trunk@1571008 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES.txt b/CHANGES.txt
index 5fceee9..0c803db 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,10 +3,9 @@
 
 ======================= 1.2-dev =====================
 
-CONNECTORS-886: Provide [allow|deny]_token_directory_N fields.
-With mcf.auth.directoryCount param, we can control
-token_directory fields filtering. 
-(Shinichiro Abe)
+CONNECTORS-886: Provide [allow|deny]_token_parent fields.
+Upgrade to this version now requires reindexing.
+(Shinichiro Abe, Karl Wright)
 
 CONNECTORS-848: Build against Lucene/Solr 4.6.0.
 
diff --git a/README.txt b/README.txt
index 22d02bf..1c80c88 100644
--- a/README.txt
+++ b/README.txt
@@ -17,8 +17,17 @@
 Compatibility
 ------------
 
-This version of this component is fully functional with Apache ManifoldCF 1.5 and
-above.  It is backwards compatible with earlier versions as well.
+This version of this component is fully functional with Apache ManifoldCF 1.6 and
+above.  It is backwards compatible with earlier versions as well, except for the fact
+that two additional Solr fields are required for this plugin to work.
+
+Upgrading
+---------
+
+If you are replacing a version of Apache ManifoldCF Plugin for Apache Solr 4.x that is
+older than version 1.2, you must declare two additional fields (representing parent
+acls and parent deny acls), and reindex all your documents.  Otherwise, the plugin
+will prevent you from viewing any documents.
 
 Instructions for Building Apache ManifoldCF Plugin for Apache Solr 4.x from Source
 ------------------------------------------------------------------------------
diff --git a/mcf/README.txt b/mcf/README.txt
index 6d0bbe7..3bec3e7 100644
--- a/mcf/README.txt
+++ b/mcf/README.txt
@@ -16,30 +16,48 @@
 Compatibility
 ------------
 
-This version of this component is only compatible with ManifoldCF 1.5 and above, and cannot be used with earlier releases of ManifoldCF.
+This version of this component is fully functional with Apache ManifoldCF 1.6 and
+above.  It is backwards compatible with earlier versions as well, except for the fact
+that two additional Solr fields are required for this plugin to work.
+
 
 Getting Started
 ---------------
 
-There are two ways to hook up security to Solr in this package.  The first is using a Query Parser plugin.
-The second is using a Search Component.  In both cases, the first step is to have ManifoldCF installed and running.  See:
+There are two ways to hook up security to Solr in this package.  The first is using
+a Query Parser plugin.  The second is using a Search Component.  In both cases,
+the first step is to have ManifoldCF installed and running.  See:
 http://manifoldcf.apache.org/release/trunk/en_US/how-to-build-and-deploy.html
 
-Then, you will need to add fields to your Solr schema.xml file that can be used to contain document
-authorization information.  There will need to be four of these fields, an 'allow' field for both
-documents and shares, and a 'deny' field for both documents and shares.  For example:
+Then, you will need to add fields to your Solr schema.xml file that can be used
+to contain document authorization information.  There will need to be six of these
+fields, an 'allow' field for documents, parents, and shares, and a 'deny' field for
+documents, parents, and shares.  For example:
 
-  <field name="allow_token_document" type="string" indexed="true" stored="false" multiValued="true" required="false" default="__nosecurity__"/>
-  <field name="allow_token_share" type="string" indexed="true" stored="false" multiValued="true" required="false" default="__nosecurity__"/>
-  <field name="deny_token_document" type="string" indexed="true" stored="false" multiValued="true" required="false" default="__nosecurity__"/>
-  <field name="deny_token_share" type="string" indexed="true" stored="false" multiValued="true" required="false" default="__nosecurity__"/>
+  <field name="allow_token_document" type="string" indexed="true" stored="false"
+    multiValued="true" required="false" default="__nosecurity__"/>
+  <field name="allow_token_parent" type="string" indexed="true" stored="false"
+    multiValued="true" required="false" default="__nosecurity__"/>
+  <field name="allow_token_share" type="string" indexed="true" stored="false"
+    multiValued="true" required="false" default="__nosecurity__"/>
+  <field name="deny_token_document" type="string" indexed="true" stored="false"
+    multiValued="true" required="false" default="__nosecurity__"/>
+  <field name="deny_token_parent" type="string" indexed="true" stored="false"
+    multiValued="true" required="false" default="__nosecurity__"/>
+  <field name="deny_token_share" type="string" indexed="true" stored="false"
+    multiValued="true" required="false" default="__nosecurity__"/>
 
-If needed, there will need to plus two of these fields for directory.
-[allow|deny]_token_directory_N. N is the number that is greater than or equal to zero.
-Currently directory_0 is supported in Jcifs connector. 
+The default value of "__nosecurity__" is required by this plugin, so do not forget
+to include it.
 
-  <field name="allow_token_directory_0" type="string" indexed="true" stored="false" multiValued="true" required="false" default="__nosecurity__"/>
-  <field name="deny_token_directory_0" type="string" indexed="true" stored="false" multiValued="true" required="false" default="__nosecurity__"/>
+
+Upgrading from releases earlier than 1.2
+--------------------------------------
+
+Earlier releases of this plugin only required four special fields.  Since this version
+of the plugin requires six, when upgrading it will be necessary to reindex all
+documents, so all six fields have the correct values.  Otherwise, the plugin
+will prevent you from viewing any documents.
 
 
 Using the Query Parser Plugin
@@ -86,21 +104,6 @@
 </requestHandler>
 
 
-Supplying token_directory for filtering
-----------------------------------------------
-
-This component looks for the following parameter in the Solr request object:
-
-mcf.auth.directoryCount
-
-If you do not use [allow|deny]_token_directory_N fields in your schema.xml,
-you may specify 0. Default to 0.
-You can specify the count of directory_N pairs. When using directory_0, set to 1. 
-Using this parameter value, this component will filter documents.
-If null or 0, then the filtering by share, document.
-If 1, then the filtering by share, direcory_0, document.
-If 2, then the filtering by share, direcory_0, direcory_1, document.
-
 Supplying authenticated usernames and domains
 ----------------------------------------------
 
diff --git a/mcf/src/java/org/apache/solr/mcf/ManifoldCFQParserPlugin.java b/mcf/src/java/org/apache/solr/mcf/ManifoldCFQParserPlugin.java
index 886ebfd..ff505c3 100644
--- a/mcf/src/java/org/apache/solr/mcf/ManifoldCFQParserPlugin.java
+++ b/mcf/src/java/org/apache/solr/mcf/ManifoldCFQParserPlugin.java
@@ -72,9 +72,6 @@
   /** If there are more than one user/domain, this prefix will allow us to get the authorization domains... */
   static final public String AUTHENTICATED_USER_DOMAIN_PREFIX = "AuthenticatedUserDomain_";
 
-  /** The parameter that is supposed to contain token_directory for filtering */
-  static final public String AUTH_DIRECTORYCOUNT = COMPONENT_NAME+".auth.directoryCount";
-
   /** This parameter is an array of strings, which contain the tokens to use if there is no authenticated user name.
    * It's meant to work with mod_authz_annotate,
    * running under Apache */
@@ -95,8 +92,8 @@
   String fieldDenyDocument = null;
   String fieldAllowShare = null;
   String fieldDenyShare = null;
-  String fieldAllowDirectory = null;
-  String fieldDenyDirectory = null;
+  String fieldAllowParent = null;
+  String fieldDenyParent = null;
   int connectionTimeOut;
   int socketTimeOut;
   Integer connectionManagerSynchronizer = new Integer(0);
@@ -129,8 +126,8 @@
     fieldDenyDocument = denyAttributePrefix+"document";
     fieldAllowShare = allowAttributePrefix+"share";
     fieldDenyShare = denyAttributePrefix+"share";
-    fieldAllowDirectory = allowAttributePrefix+"directory_";
-    fieldDenyDirectory = denyAttributePrefix+"directory_";
+    fieldAllowParent = allowAttributePrefix+"parent";
+    fieldDenyParent = denyAttributePrefix+"parent";
     Integer connectionPoolSize = (Integer)args.get("ConnectionPoolSize");
     poolSize = (connectionPoolSize==null)?50:connectionPoolSize.intValue();
   }
@@ -263,25 +260,13 @@
         }
       }
 
-      // Get the auth directory field count from the parameter
-      int directoryCount = params.getInt(AUTH_DIRECTORYCOUNT, 0);
-
       BooleanQuery bq = new BooleanQuery();
       //bf.setMaxClauseCount(100000);
       
       Query allowShareOpen = new TermQuery(new Term(fieldAllowShare,NOSECURITY_TOKEN));
       Query denyShareOpen = new TermQuery(new Term(fieldDenyShare,NOSECURITY_TOKEN));
-      Map<Integer,Query> allowDirectoryOpenMap = new HashMap<Integer,Query>();
-      Map<Integer,Query> denyDirectoryOpenMap = new HashMap<Integer,Query>();
-      int q = 0;
-      while (q < directoryCount)
-      {
-        Query allowDirectoryOpen = new TermQuery(new Term(fieldAllowDirectory+q,NOSECURITY_TOKEN));
-        Query denyDirectoryOpen = new TermQuery(new Term(fieldDenyDirectory+q,NOSECURITY_TOKEN));
-        allowDirectoryOpenMap.put(Integer.valueOf(q), allowDirectoryOpen);
-        denyDirectoryOpenMap.put(Integer.valueOf(q), denyDirectoryOpen);
-        q++;
-      }
+      Query allowParentOpen = new TermQuery(new Term(fieldAllowParent,NOSECURITY_TOKEN));
+      Query denyParentOpen = new TermQuery(new Term(fieldDenyParent,NOSECURITY_TOKEN));
       Query allowDocumentOpen = new TermQuery(new Term(fieldAllowDocument,NOSECURITY_TOKEN));
       Query denyDocumentOpen = new TermQuery(new Term(fieldDenyDocument,NOSECURITY_TOKEN));
       
@@ -294,16 +279,8 @@
         // have the SolrConnector inject a special token into these fields when they otherwise would be empty, and we can trivially match on that token.
         bq.add(allowShareOpen,BooleanClause.Occur.MUST);
         bq.add(denyShareOpen,BooleanClause.Occur.MUST);
-        int r = 0;
-        while (r < directoryCount)
-        {
-          Integer index = Integer.valueOf(r);
-          Query allowDirectoryOpen = allowDirectoryOpenMap.get(index);
-          Query denyDirectoryOpen = denyDirectoryOpenMap.get(index);
-          bq.add(allowDirectoryOpen,BooleanClause.Occur.MUST);
-          bq.add(denyDirectoryOpen,BooleanClause.Occur.MUST);
-          r++;
-        }
+        bq.add(allowParentOpen,BooleanClause.Occur.MUST);
+        bq.add(denyParentOpen,BooleanClause.Occur.MUST);
         bq.add(allowDocumentOpen,BooleanClause.Occur.MUST);
         bq.add(denyDocumentOpen,BooleanClause.Occur.MUST);
       }
@@ -312,16 +289,8 @@
         // Extend the query appropriately for each user access token.
         bq.add(calculateCompleteSubquery(fieldAllowShare,fieldDenyShare,allowShareOpen,denyShareOpen,userAccessTokens),
           BooleanClause.Occur.MUST);
-        int r = 0;
-        while (r < directoryCount)
-        {
-          Integer index = Integer.valueOf(r);
-          Query allowDirectoryOpen = allowDirectoryOpenMap.get(index);
-          Query denyDirectoryOpen = denyDirectoryOpenMap.get(index);
-          bq.add(calculateCompleteSubquery(fieldAllowDirectory+r,fieldDenyDirectory+r,allowDirectoryOpen,denyDirectoryOpen,userAccessTokens),
-            BooleanClause.Occur.MUST);
-          r++;
-        }
+        bq.add(calculateCompleteSubquery(fieldAllowParent,fieldDenyParent,allowParentOpen,denyParentOpen,userAccessTokens),
+          BooleanClause.Occur.MUST);
         bq.add(calculateCompleteSubquery(fieldAllowDocument,fieldDenyDocument,allowDocumentOpen,denyDocumentOpen,userAccessTokens),
           BooleanClause.Occur.MUST);
       }
diff --git a/mcf/src/java/org/apache/solr/mcf/ManifoldCFSearchComponent.java b/mcf/src/java/org/apache/solr/mcf/ManifoldCFSearchComponent.java
index 0abe625..11177e8 100644
--- a/mcf/src/java/org/apache/solr/mcf/ManifoldCFSearchComponent.java
+++ b/mcf/src/java/org/apache/solr/mcf/ManifoldCFSearchComponent.java
@@ -65,9 +65,6 @@
   /** If there are more than one user/domain, this prefix will allow us to get the authorization domains... */
   static final public String AUTHENTICATED_USER_DOMAIN_PREFIX = "AuthenticatedUserDomain_";
 
-  /** The parameter that is supposed to contain token_directory for filtering */
-  static final public String AUTH_DIRECTORYCOUNT = COMPONENT_NAME+".auth.directoryCount";
-
   /** This parameter is an array of strings, which contain the tokens to use if there is no authenticated user name.
    * It's meant to work with mod_authz_annotate,
    * running under Apache */
@@ -88,8 +85,8 @@
   String fieldDenyDocument = null;
   String fieldAllowShare = null;
   String fieldDenyShare = null;
-  String fieldAllowDirectory = null;
-  String fieldDenyDirectory = null;
+  String fieldAllowParent = null;
+  String fieldDenyParent = null;
   int connectionTimeOut;
   int socketTimeOut;
   ThreadSafeClientConnManager httpConnectionManager = null;
@@ -125,8 +122,8 @@
     fieldDenyDocument = denyAttributePrefix+"document";
     fieldAllowShare = allowAttributePrefix+"share";
     fieldDenyShare = denyAttributePrefix+"share";
-    fieldAllowDirectory = allowAttributePrefix+"directory_";
-    fieldDenyDirectory = denyAttributePrefix+"directory_";
+    fieldAllowParent = allowAttributePrefix+"parent";
+    fieldDenyParent = denyAttributePrefix+"parent";
     Integer connectionPoolSize = (Integer)args.get("ConnectionPoolSize");
     poolSize = (connectionPoolSize==null)?50:connectionPoolSize.intValue();
 
@@ -241,25 +238,13 @@
       userAccessTokens = getAccessTokens(domainMap);
     }
 
-    // Get the auth directory field count from the parameter
-    int directoryCount = params.getInt(AUTH_DIRECTORYCOUNT, 0);
-
     BooleanQuery bq = new BooleanQuery();
     //bf.setMaxClauseCount(100000);
     
     Query allowShareOpen = new TermQuery(new Term(fieldAllowShare,NOSECURITY_TOKEN));
     Query denyShareOpen = new TermQuery(new Term(fieldDenyShare,NOSECURITY_TOKEN));
-    Map<Integer,Query> allowDirectoryOpenMap = new HashMap<Integer,Query>();
-    Map<Integer,Query> denyDirectoryOpenMap = new HashMap<Integer,Query>();
-    int q = 0;
-    while (q < directoryCount)
-    {
-      Query allowDirectoryOpen = new TermQuery(new Term(fieldAllowDirectory+q,NOSECURITY_TOKEN));
-      Query denyDirectoryOpen = new TermQuery(new Term(fieldDenyDirectory+q,NOSECURITY_TOKEN));
-      allowDirectoryOpenMap.put(Integer.valueOf(q), allowDirectoryOpen);
-      denyDirectoryOpenMap.put(Integer.valueOf(q), denyDirectoryOpen);
-      q++;
-    }
+    Query allowParentOpen = new TermQuery(new Term(fieldAllowParent,NOSECURITY_TOKEN));
+    Query denyParentOpen = new TermQuery(new Term(fieldDenyParent,NOSECURITY_TOKEN));
     Query allowDocumentOpen = new TermQuery(new Term(fieldAllowDocument,NOSECURITY_TOKEN));
     Query denyDocumentOpen = new TermQuery(new Term(fieldDenyDocument,NOSECURITY_TOKEN));
     
@@ -272,16 +257,8 @@
       // have the SolrConnector inject a special token into these fields when they otherwise would be empty, and we can trivially match on that token.
       bq.add(allowShareOpen,BooleanClause.Occur.MUST);
       bq.add(denyShareOpen,BooleanClause.Occur.MUST);
-      int r = 0;
-      while (r < directoryCount)
-      {
-        Integer index = Integer.valueOf(r);
-        Query allowDirectoryOpen = allowDirectoryOpenMap.get(index);
-        Query denyDirectoryOpen = denyDirectoryOpenMap.get(index);
-        bq.add(allowDirectoryOpen,BooleanClause.Occur.MUST);
-        bq.add(denyDirectoryOpen,BooleanClause.Occur.MUST);
-        r++;
-      }
+      bq.add(allowParentOpen,BooleanClause.Occur.MUST);
+      bq.add(denyParentOpen,BooleanClause.Occur.MUST);
       bq.add(allowDocumentOpen,BooleanClause.Occur.MUST);
       bq.add(denyDocumentOpen,BooleanClause.Occur.MUST);
     }
@@ -290,16 +267,8 @@
       // Extend the query appropriately for each user access token.
       bq.add(calculateCompleteSubquery(fieldAllowShare,fieldDenyShare,allowShareOpen,denyShareOpen,userAccessTokens),
         BooleanClause.Occur.MUST);
-      int r = 0;
-      while (r < directoryCount)
-      {
-        Integer index = Integer.valueOf(r);
-        Query allowDirectoryOpen = allowDirectoryOpenMap.get(index);
-        Query denyDirectoryOpen = denyDirectoryOpenMap.get(index);
-        bq.add(calculateCompleteSubquery(fieldAllowDirectory+r,fieldDenyDirectory+r,allowDirectoryOpen,denyDirectoryOpen,userAccessTokens),
-          BooleanClause.Occur.MUST);
-        r++;
-      }
+      bq.add(calculateCompleteSubquery(fieldAllowParent,fieldDenyParent,allowParentOpen,denyParentOpen,userAccessTokens),
+        BooleanClause.Occur.MUST);
       bq.add(calculateCompleteSubquery(fieldAllowDocument,fieldDenyDocument,allowDocumentOpen,denyDocumentOpen,userAccessTokens),
         BooleanClause.Occur.MUST);
     }
diff --git a/mcf/src/test-files/solr-mcf/solr/collection1/conf/schema-auth.xml b/mcf/src/test-files/solr-mcf/solr/collection1/conf/schema-auth.xml
index 3d092cd..eeca091 100644
--- a/mcf/src/test-files/solr-mcf/solr/collection1/conf/schema-auth.xml
+++ b/mcf/src/test-files/solr-mcf/solr/collection1/conf/schema-auth.xml
@@ -26,8 +26,8 @@
   <field name="deny_token_document" type="string" indexed="true" stored="false" multiValued="true" default="__nosecurity__"/>
   <field name="allow_token_share" type="string" indexed="true" stored="false" multiValued="true" default="__nosecurity__"/>
   <field name="deny_token_share" type="string" indexed="true" stored="false" multiValued="true" default="__nosecurity__"/>
-  <field name="allow_token_directory_0" type="string" indexed="true" stored="false" multiValued="true" default="__nosecurity__"/>
-  <field name="deny_token_directory_0" type="string" indexed="true" stored="false" multiValued="true" default="__nosecurity__"/>
+  <field name="allow_token_parent" type="string" indexed="true" stored="false" multiValued="true" default="__nosecurity__"/>
+  <field name="deny_token_parent" type="string" indexed="true" stored="false" multiValued="true" default="__nosecurity__"/>
  </fields>
  <defaultSearchField>id</defaultSearchField>
  <uniqueKey>id</uniqueKey>
diff --git a/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth-load.xml b/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth-load.xml
index d009ed3..ed0304a 100644
--- a/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth-load.xml
+++ b/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth-load.xml
@@ -51,7 +51,6 @@
   <requestHandler name="/mcf" class="solr.SearchHandler" startup="lazy">
     <lst name="invariants">
       <bool name="mcf">true</bool>
-      <int name="mcf.auth.directoryCount">1</int>
     </lst>
     <lst name="defaults">
       <str name="echoParams">all</str>
diff --git a/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth-qparser.xml b/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth-qparser.xml
index cb1c6e2..edfae47 100644
--- a/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth-qparser.xml
+++ b/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth-qparser.xml
@@ -51,7 +51,6 @@
   <requestHandler name="/mcf" class="solr.SearchHandler" startup="lazy">
     <lst name="invariants">
       <bool name="mcf">true</bool>
-      <int name="mcf.auth.derectoryCount">1</int>
     </lst>
     <lst name="defaults">
       <str name="echoParams">all</str>
diff --git a/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth.xml b/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth.xml
index 384b0fc..106c2b6 100644
--- a/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth.xml
+++ b/mcf/src/test-files/solr-mcf/solr/collection1/conf/solrconfig-auth.xml
@@ -50,7 +50,6 @@
   <requestHandler name="/mcf" class="solr.SearchHandler" startup="lazy">
     <lst name="invariants">
       <bool name="mcf">true</bool>
-      <int name="mcf.auth.directoryCount">1</int>
     </lst>
     <lst name="defaults">
       <str name="echoParams">all</str>