You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by us...@apache.org on 2015/07/01 02:16:38 UTC

svn commit: r1688537 - in /lucene/dev/trunk/lucene: ./ core/src/java/org/apache/lucene/store/ core/src/test/org/apache/lucene/index/ test-framework/src/java/org/apache/lucene/util/ test-framework/src/test/org/apache/lucene/util/ tools/junit4/

Author: uschindler
Date: Wed Jul  1 00:16:37 2015
New Revision: 1688537

URL: http://svn.apache.org/r1688537
Log:
LUCENE-6542: FSDirectory's ctor now works with security policies or file systems that restrict write access

Added:
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/index/TestReadOnlyIndex.java   (with props)
    lucene/dev/trunk/lucene/test-framework/src/test/org/apache/lucene/util/TestRunWithRestrictedPermissions.java   (with props)
Modified:
    lucene/dev/trunk/lucene/CHANGES.txt
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/store/FSDirectory.java
    lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
    lucene/dev/trunk/lucene/tools/junit4/tests.policy

Modified: lucene/dev/trunk/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=1688537&r1=1688536&r2=1688537&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/CHANGES.txt Wed Jul  1 00:16:37 2015
@@ -232,6 +232,9 @@ Changes in Runtime Behavior
   API, however the returned bits may be called on different documents compared
   to before. (Adrien Grand)
 
+* LUCENE-6542: FSDirectory's ctor now works with security policies or file systems
+  that restrict write access.  (Trejkaz, hossman, Uwe Schindler)
+
 Optimizations
 
 * LUCENE-6548: Some optimizations for BlockTree's intersect with very
@@ -264,6 +267,11 @@ Test Framework
 * LUCENE-6637: Fix FSTTester to not violate file permissions on
   -Dtests.verbose=true.  (Mesbah M. Alam, Uwe Schindler)
 
+* LUCENE-6542: LuceneTestCase now has runWithRestrictedPermissions() to run
+  an action with reduced permissions. This can be used to simulate special
+  environments (e.g., read-only dirs). If tests are running without a security
+  manager, an assume cancels test execution automatically.  (Uwe Schindler)
+
 Changes in Backwards Compatibility Policy
 
 * LUCENE-6553: The iterator returned by the LeafReader.postings method now

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/store/FSDirectory.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/store/FSDirectory.java?rev=1688537&r1=1688536&r2=1688537&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/store/FSDirectory.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/store/FSDirectory.java Wed Jul  1 00:16:37 2015
@@ -125,7 +125,10 @@ public abstract class FSDirectory extend
    */
   protected FSDirectory(Path path, LockFactory lockFactory) throws IOException {
     super(lockFactory);
-    Files.createDirectories(path);  // create directory, if it doesn't exist
+    // If only read access is permitted, createDirectories fails even if the directory already exists.
+    if (!Files.isDirectory(path)) {
+      Files.createDirectories(path);  // create directory, if it doesn't exist
+    }
     directory = path.toRealPath();
   }
 

Added: lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/index/TestReadOnlyIndex.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/index/TestReadOnlyIndex.java?rev=1688537&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/index/TestReadOnlyIndex.java (added)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/index/TestReadOnlyIndex.java Wed Jul  1 00:16:37 2015
@@ -0,0 +1,98 @@
+package org.apache.lucene.index;
+
+/*
+ * 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.io.FilePermission;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.PropertyPermission;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.MockAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.PhraseQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.BeforeClass;
+
+public class TestReadOnlyIndex extends LuceneTestCase {
+
+  private static final String longTerm = "longtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongtermlongterm";
+  private static final String text = "This is the text to be indexed. " + longTerm;
+
+  private static Path indexPath;  
+
+  @BeforeClass
+  public static void buildIndex() throws Exception {
+    indexPath = Files.createTempDirectory("readonlyindex");
+    
+    // borrows from TestDemo, but not important to keep in sync with demo
+    Analyzer analyzer = new MockAnalyzer(random());
+    Directory directory = newFSDirectory(indexPath);
+    RandomIndexWriter iwriter = new RandomIndexWriter(random(), directory, analyzer);
+    Document doc = new Document();
+    doc.add(newTextField("fieldname", text, Field.Store.YES));
+    iwriter.addDocument(doc);
+    iwriter.close();
+    directory.close();
+    analyzer.close();
+  }
+  
+  public void testReadOnlyIndex() throws Exception {
+    runWithRestrictedPermissions(this::doTestReadOnlyIndex,
+        // add some basic permissions (because we are limited already - so we grant all important ones):
+        new RuntimePermission("*"),
+        new PropertyPermission("*", "read"),
+        // only allow read to the given index dir, nothing else:
+        new FilePermission(indexPath.toString(), "read"),
+        new FilePermission(indexPath.resolve("-").toString(), "read")
+    );
+  }
+  
+  private Void doTestReadOnlyIndex() throws Exception {
+    Directory dir = FSDirectory.open(indexPath); 
+    IndexReader ireader = DirectoryReader.open(dir); 
+    IndexSearcher isearcher = newSearcher(ireader);
+    
+    // borrows from TestDemo, but not important to keep in sync with demo
+
+    assertEquals(1, isearcher.search(new TermQuery(new Term("fieldname", longTerm)), 1).totalHits);
+    Query query = new TermQuery(new Term("fieldname", "text"));
+    TopDocs hits = isearcher.search(query, 1);
+    assertEquals(1, hits.totalHits);
+    // Iterate through the results:
+    for (int i = 0; i < hits.scoreDocs.length; i++) {
+      StoredDocument hitDoc = isearcher.doc(hits.scoreDocs[i].doc);
+      assertEquals(text, hitDoc.get("fieldname"));
+    }
+
+    // Test simple phrase query
+    PhraseQuery phraseQuery = new PhraseQuery("fieldname", "to", "be");
+    assertEquals(1, isearcher.search(phraseQuery, 1).totalHits);
+
+    ireader.close();
+    return null; // void
+  }
+  
+}

Modified: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java?rev=1688537&r1=1688536&r2=1688537&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java (original)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java Wed Jul  1 00:16:37 2015
@@ -34,6 +34,14 @@ import java.lang.reflect.Method;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -101,6 +109,7 @@ import org.junit.Test;
 import org.junit.rules.RuleChain;
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
+
 import com.carrotsearch.randomizedtesting.JUnit4MethodProvider;
 import com.carrotsearch.randomizedtesting.LifecycleScope;
 import com.carrotsearch.randomizedtesting.MixWithSuiteName;
@@ -2604,6 +2613,25 @@ public abstract class LuceneTestCase ext
   public static Path createTempFile() throws IOException {
     return createTempFile("tempFile", ".tmp");
   }
+  
+  /** 
+   * Runs a code part with restricted permissions (be sure to add all required permissions,
+   * because it would start with empty permissions). You cannot grant more permissions than
+   * our policy file allows, but you may restrict writing to several dirs...
+   * <p><em>Note:</em> This assumes a {@link SecurityManager} enabled, otherwise it
+   * stops test execution.
+   */
+  public static <T> T runWithRestrictedPermissions(PrivilegedExceptionAction<T> action, Permission... permissions) throws Exception {
+    assumeTrue("runWithRestrictedPermissions requires a SecurityManager enabled", System.getSecurityManager() != null);
+    final PermissionCollection perms = new Permissions();
+    Arrays.stream(permissions).forEach(perms::add);
+    final AccessControlContext ctx = new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
+    try {
+      return AccessController.doPrivileged(action, ctx);
+    } catch (PrivilegedActionException e) {
+      throw e.getException();
+    }
+  }
 
   /** True if assertions (-ea) are enabled (at least for this class). */
   public static final boolean assertsAreEnabled;

Added: lucene/dev/trunk/lucene/test-framework/src/test/org/apache/lucene/util/TestRunWithRestrictedPermissions.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/test/org/apache/lucene/util/TestRunWithRestrictedPermissions.java?rev=1688537&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/test/org/apache/lucene/util/TestRunWithRestrictedPermissions.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/test/org/apache/lucene/util/TestRunWithRestrictedPermissions.java Wed Jul  1 00:16:37 2015
@@ -0,0 +1,69 @@
+package org.apache.lucene.util;
+
+/*
+ * 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.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.AllPermission;
+
+public class TestRunWithRestrictedPermissions extends LuceneTestCase {
+
+  public void testDefaultsPass() throws Exception {
+    runWithRestrictedPermissions(this::doSomeForbiddenStuff, new AllPermission());
+  }
+
+  public void testNormallyAllowedStuff() throws Exception {
+    try {
+      runWithRestrictedPermissions(this::doSomeForbiddenStuff);
+      fail("this should not pass!");
+    } catch (SecurityException se) {
+      // pass
+    }
+  }
+
+  public void testCompletelyForbidden1() throws Exception {
+    try {
+      runWithRestrictedPermissions(this::doSomeCompletelyForbiddenStuff);
+      fail("this should not pass!");
+    } catch (SecurityException se) {
+      // pass
+    }
+  }
+
+  public void testCompletelyForbidden2() throws Exception {
+    try {
+      runWithRestrictedPermissions(this::doSomeCompletelyForbiddenStuff, new AllPermission());
+      fail("this should not pass (not even with AllPermission)");
+    } catch (SecurityException se) {
+      // pass
+    }
+  }
+
+  private Void doSomeForbiddenStuff() throws IOException {
+    createTempDir("cannot_create_temp_folder");
+    return null; // Void
+  }
+  
+  // something like this should not never pass!!
+  private Void doSomeCompletelyForbiddenStuff() throws IOException {
+    Files.createFile(Paths.get("denied"));
+    return null; // Void
+  }
+  
+}

Modified: lucene/dev/trunk/lucene/tools/junit4/tests.policy
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/tools/junit4/tests.policy?rev=1688537&r1=1688536&r2=1688537&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/tools/junit4/tests.policy (original)
+++ lucene/dev/trunk/lucene/tools/junit4/tests.policy Wed Jul  1 00:16:37 2015
@@ -110,4 +110,7 @@ grant {
   // SSL related properties for jetty
   permission java.security.SecurityPermission "getProperty.ssl.KeyManagerFactory.algorithm";
   permission java.security.SecurityPermission "getProperty.ssl.TrustManagerFactory.algorithm";
+  
+  // allows LuceneTestCase#runWithRestrictedPermissions to execute with lower (or no) permission
+  permission java.security.SecurityPermission "createAccessControlContext";
 };