mirror of https://github.com/apache/lucene.git
LUCENE-6921: Fix SPIClassIterator#isParentClassLoader to don't require extra permissions
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1718078 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4394851104
commit
9d4c415450
|
@ -138,6 +138,9 @@ Other
|
||||||
to use MethodHandles and work without extra security privileges.
|
to use MethodHandles and work without extra security privileges.
|
||||||
(Uwe Schindler, Robert Muir)
|
(Uwe Schindler, Robert Muir)
|
||||||
|
|
||||||
|
* LUCENE-6921: Fix SPIClassIterator#isParentClassLoader to don't
|
||||||
|
require extra permissions. (Uwe Schindler)
|
||||||
|
|
||||||
======================= Lucene 5.4.0 =======================
|
======================= Lucene 5.4.0 =======================
|
||||||
|
|
||||||
New Features
|
New Features
|
||||||
|
|
|
@ -23,12 +23,15 @@ import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.ServiceConfigurationError;
|
import java.util.ServiceConfigurationError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,35 +50,51 @@ public final class SPIClassIterator<S> implements Iterator<Class<? extends S>> {
|
||||||
private final Enumeration<URL> profilesEnum;
|
private final Enumeration<URL> profilesEnum;
|
||||||
private Iterator<String> linesIterator;
|
private Iterator<String> linesIterator;
|
||||||
|
|
||||||
|
/** Creates a new SPI iterator to lookup services of type {@code clazz} using the context classloader. */
|
||||||
public static <S> SPIClassIterator<S> get(Class<S> clazz) {
|
public static <S> SPIClassIterator<S> get(Class<S> clazz) {
|
||||||
return new SPIClassIterator<>(clazz, Thread.currentThread().getContextClassLoader());
|
return new SPIClassIterator<>(clazz, Thread.currentThread().getContextClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Creates a new SPI iterator to lookup services of type {@code clazz} using the given classloader. */
|
||||||
public static <S> SPIClassIterator<S> get(Class<S> clazz, ClassLoader loader) {
|
public static <S> SPIClassIterator<S> get(Class<S> clazz, ClassLoader loader) {
|
||||||
return new SPIClassIterator<>(clazz, loader);
|
return new SPIClassIterator<>(clazz, loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Utility method to check if some class loader is a (grand-)parent of or the same as another one.
|
/**
|
||||||
* This means the child will be able to load all classes from the parent, too. */
|
* Utility method to check if some class loader is a (grand-)parent of or the same as another one.
|
||||||
public static boolean isParentClassLoader(final ClassLoader parent, ClassLoader child) {
|
* This means the child will be able to load all classes from the parent, too.
|
||||||
while (child != null) {
|
* <p>
|
||||||
if (child == parent) {
|
* If Lucene's codebase doesn't have enough permissions to do the check, {@code false} is returned.
|
||||||
|
*/
|
||||||
|
public static boolean isParentClassLoader(final ClassLoader parent, final ClassLoader child) {
|
||||||
|
if (parent == child) {
|
||||||
|
return true; // don't try to use AccessController for performance
|
||||||
|
}
|
||||||
|
return AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> {
|
||||||
|
try {
|
||||||
|
ClassLoader cl = child;
|
||||||
|
while (cl != null) {
|
||||||
|
if (cl == parent) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
child = child.getParent();
|
cl = cl.getParent();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
} catch (SecurityException se) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private SPIClassIterator(Class<S> clazz, ClassLoader loader) {
|
private SPIClassIterator(Class<S> clazz, ClassLoader loader) {
|
||||||
this.clazz = clazz;
|
this.clazz = Objects.requireNonNull(clazz, "clazz");
|
||||||
|
this.loader = Objects.requireNonNull(loader, "loader");
|
||||||
try {
|
try {
|
||||||
final String fullName = META_INF_SERVICES + clazz.getName();
|
final String fullName = META_INF_SERVICES + clazz.getName();
|
||||||
this.profilesEnum = (loader == null) ? ClassLoader.getSystemResources(fullName) : loader.getResources(fullName);
|
this.profilesEnum = loader.getResources(fullName);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new ServiceConfigurationError("Error loading SPI profiles for type " + clazz.getName() + " from classpath", ioe);
|
throw new ServiceConfigurationError("Error loading SPI profiles for type " + clazz.getName() + " from classpath", ioe);
|
||||||
}
|
}
|
||||||
this.loader = (loader == null) ? ClassLoader.getSystemClassLoader() : loader;
|
|
||||||
this.linesIterator = Collections.<String>emptySet().iterator();
|
this.linesIterator = Collections.<String>emptySet().iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
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.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
public class TestSPIClassIterator extends LuceneTestCase {
|
||||||
|
|
||||||
|
public void testParentChild() throws Exception {
|
||||||
|
final ClassLoader parent = getClass().getClassLoader();
|
||||||
|
final ClassLoader child = URLClassLoader.newInstance(new URL[0], parent);
|
||||||
|
assertTrue(checkNoPerms(parent, parent));
|
||||||
|
assertTrue(checkNoPerms(child, child));
|
||||||
|
assertTrue(checkNoPerms(parent, child));
|
||||||
|
assertFalse(checkNoPerms(child, parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkNoPerms(ClassLoader parent, ClassLoader child) throws Exception {
|
||||||
|
return runWithRestrictedPermissions(() -> SPIClassIterator.isParentClassLoader(parent, child));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue