Security: Restrict internal access by third-party software - java

I have a Java application in which third-party "plugins" can be loaded by users to enhance the user experience. An API exists for use by these plugins, but the third-party software should be restricted from access to internal application classes for purpose of security. The restricted package to plugins would be "com.example" and the allowed would be "com.example.api". The API classes do make calls to the internal, obfuscated classes.
After researching this, I came across a couple methods of SecurityManager: checkMemberAccess(Class, int) and checkPackageAccess(String), which both seemed to be viable paths to my goal. However, after doing some tests and further research, I have found that checkMemberAccess only applies to reflection calls, and checkPackageAccess is only called when a class loader invokes loadClass.
What is a reasonable way to restrict access to a package (com.example, but not com.example.api)?

I suggest writing a custom class loader for the plugins, which hides the existence of the com.example package from classes loaded using that classloader. Usually class loaders delegate to their parent, but there are several implementations out in the wild which will do so only in part or not at all. I believe e.g. ant uses this technique. When loaded with such a class loader, any class linked against forbidden functinality would fail to load. Or if the implementation used lazy linking, and it did load successfully, it would still fail during execution of the forbidden code.
Having denied your plugins link-time access to the forbidden package, you can then use a SecurityManager to deny runtime access via reflection, and also to deny creation of a new class loader which might be used to circumvent yours.
class RestrictingClassLoader extends URLClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (!name.startsWith("com.example.") || name.startsWith("com.example.api."))
return super.loadClass(name);
return findClass(name);
}
}
class RestrictingSecurityManager extends SecurityManager {
private boolean isRestricted() {
for (Class<?> cls: getClassContext())
if (cls.getClassLoader() instanceof RestrictingClassLoader)
return true;
return false;
}
// Implement other checks based on isRestricted().
}

Related

Fix classloading issue with ByteBuddy and Vaadin in OSGi setup

I have issues with Vaadin flow in an OSGi setup and it seems to be related to the way some classes are loaded in the internals, when using Polymer Templates.
Here is my issue with some details https://github.com/vaadin/flow/issues/7377.
In TemplateModelProxyHandler:229ff the following code is used to load the Proxy Class
Class<?> proxyType = proxyBuilder
// Handle bean methods (and abstract methods for error handling)
.method(method -> isAccessor(method) || method.isAbstract())
.intercept(MethodDelegation.to(proxyHandler))
// Handle internal $stateNode methods
.defineField("$stateNode", StateNode.class)
.method(method -> "$stateNode".equals(method.getName()))
.intercept(FieldAccessor.ofField("$stateNode"))
// Handle internal $modelType methods
.defineField("$modelType", BeanModelType.class)
.method(method -> "$modelType".equals(method.getName()))
.intercept(FieldAccessor.ofField("$modelType"))
// Create the class
.name(proxyClassName).make()
.load(classLoader, ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
Here, two Class Loaders are important. First, the OSGi Bundle ClassLoader (classLoader) here. Second, the classloader of the Bundle which contains the class TemplateModelProxyHandler, e.g. TemplateModelProxyHandler.class.getClassLoader().
Is there a way to use both classloaders here?
Is there a simple method to achieve that with ByteBuddy?
Have a look into the MultipleParentClassLoader that is shipped with Byte Buddy. It allows you to specify multiple parents to a class loader and define a class within it.

Specification of behavior when annotation missing from classpath is attached to a class

I am looking for a specification of what the behavior will be when a Java class is annotated with an annotation that is not present on the consumer's classpath. Specifically, when the annotated class is packaged as a jar and pulled in to another project (in Maven terms, an 'optional' or 'provided' dependency contains the annotation and the dependent elects not to depend on that).
I found an old Eclipse bug thread that mentions this: https://bugs.eclipse.org/bugs/show_bug.cgi?id=320965
My understanding is that annotations are supposed to be dropped from the class file if the annotation class isn't present.
I have observed the same behavior; that is, the class seems to load fine when the annotation is not found, but I cannot find this specified anywhere. I'm using OpenJDK.
(For those curious, the context is making a library dependency injection-friendly without tying it to a specific DI framework, so I'd like to use both CDI annotations and Guice annotations, for example, but consumers will probably not want to bring in both sets of annotations, if any at all)
Neither the Java Language Specification nor the Java Virtual Machine Specification covers this directly. The latter does not discuss annotations for verification or linking, so one could argue that missing annotation types should not cause a class loading failure. The JDK API documentation does not discuss this, except for missing classes in class-valued annotations. That looks like an omission.
The parser for user-defined (non-VM) annotations lives in sun.reflect.annotation.AnnotationParser. As you can see, unknown annotations are simply skipped:
try {
try {
sig = constPool.getUTF8At(typeIndex);
annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
} catch (IllegalArgumentException ex) {
// support obsolete early jsr175 format class files
annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex);
}
} catch (NoClassDefFoundError e) {
if (exceptionOnMissingAnnotationClass)
// note: at this point sig is "[unknown]" or VM-style
// name instead of a binary name
throw new TypeNotPresentException(sig, e);
skipAnnotation(buf, false);
return null;
}
There is also no way to detect that this happens. As a result, if you want to make sure that there are no unknown annotations present, you have to parse the class file with a different parser.

Make a class method callable from anywhere in your program but not outside programs

I created a class MyLogger that extends java.util.Logger in my project and I want each class to use the same logger therefore there is a static getLogger() method which returns a Logger object.
The plan is for this to be a jar file that can be included in other people's programs, but I don't want them to be able to use this custom logger (ie. if they want logging they need to set it up themselves with their own logger).
Is there any way to allow the MyLogger class be in its own package while allowing the rest of the classes in my project/jar be able to access the getLogger() method, but not allow classes outside my project to call it (kinda like package private, but for the whole project) or is the only way to put it in my "parent" package?
Yes, you may noticed you can not put a class into package java.util, the technology is the JSA. You could use the SecurityManager (who uses the accesscontroller). If the library who is calling the logger-event is not certified by your private certificate, it throws the unchecked AccessControlException.
You will find a good example in the FileOutputStream like this:
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(name); // throws ACE
}
To authenticate a complete JVM and disable the checks you could add the private key to jdk-xxx/jre/lib/security/cacerts (keystore).

How to reload a class so that a annotation becomes visible?

In a question I asked earlier I got to know that in order to really be sure that some annotation is present or not somewhere in a class I need to reload it with a classloader that has access to both - the annotation and the class.
Now I'm struggling with how such a classloader would work. In my setup I just have the annotation as a java.lang.Class instance and the class that might be annotated with that annotation also as a java.lang.Class instance. Both might be loaded by some different classloaders I don't know anything about (classes might be loaded remotely, so they are not on the local file system).
While searching I found this JoinClassLoader
/**
* A class loader that combines multiple class loaders into one.<br>
* The classes loaded by this class loader are associated with this class loader,
* i.e. Class.getClassLoader() points to this class loader.
* <p>
* Author Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland, www.source-code.biz<br>
* License: LGPL, http://www.gnu.org/licenses/lgpl.html<br>
* Please contact the author if you need another license.
*/
public class JoinClassLoader extends ClassLoader {
private ClassLoader[] delegateClassLoaders;
public JoinClassLoader (ClassLoader parent, ClassLoader... delegateClassLoaders) {
super (parent);
this.delegateClassLoaders = delegateClassLoaders; }
protected Class<?> findClass (String name) throws ClassNotFoundException {
// It would be easier to call the loadClass() methods of the delegateClassLoaders
// here, but we have to load the class from the byte code ourselves, because we
// need it to be associated with our class loader.
String path = name.replace('.', '/') + ".class";
URL url = findResource(path);
if (url == null) {
throw new ClassNotFoundException (name); }
ByteBuffer byteCode;
try {
byteCode = loadResource(url); }
catch (IOException e) {
throw new ClassNotFoundException (name, e); }
return defineClass(name, byteCode, null); }
// some code omitted
} // end class JoinClassLoader
So my question is this:
Given a class instance of an arbitrary class C and a class instance of an annotation class A that may be loaded by arbitrary classloaders. A JoinClassLoader is instantiated with the classloaders of C and A in this order as delegating classloaders. Will that JoinClassLoader reload class C upon invoking findClass so that annotation A is always visible when C was actually annotated with it? If not how would such a classloader actually look like?
In a question I asked earlier I got to know that in order to really be
sure that some annotation is present or not somewhere in a class I
need to reload it with a classloader that has access to both - the
annotation and the class.
Given a class that has already been loaded by a classloader which might not have had access to all the annotations, I can believe that to be true. I think you've drawn the wrong conclusion, however.
If you want to be able to reflectively analyze a class's annotations at runtime, then the best solution is not to reload it. Instead, you should ensure that it is loaded in the first place by a classloader that can also see the annotations of interest. (And if that turns out not to be sufficient, then I don't see how you can expect reloading to help.)
In any case, reloading the class gives you a different class (of the same name), even if its bytecode is identical to that of the previously-loaded version. It is tricky to use this for anything but reflective analysis, and it is very difficult to be certain that the two classes actually do have identical bytecode. Reloading certainly does not replace the existing class with the newly-loaded one. All manner of fun can ensue.

Automatic factory registration

i'm just learning java, and i meet some problems.
Here we have simple factory pattern:
public class SomeFactory {
...
public static void registerProduct(String name, Class<? extends IProduct > f)
}
public SomeProduct implements IProduct {
static {
SomeFactory.register("some product", SomeProduct.class);
}
...
}
All products should register themselves at factory.
But before using this code, all Products classes should be loaded.
I can put Class.forName() somewhere, for example in main function.
But i want to avoid such sort of manual classes loading. I want just add new IProduct
implementations, without updating other parts(such as SomeFactory or Main methods, etc.).
But i wonder, is it possible to automatically load some classes(marked with annotation, for example)?
P.S I want to notice, that no other classes will be added at run-time, all IProduct implementations are known before compiling.
UPD#1
Thank for your answering!
But is it possible to make auto-generated property-file with IProduct instances?
I mean is it possible to make some build-time script(for maven for example) that generates property-file or loader code? Are there such solutions or frameworks?
UPD#2
I finished with using Reflections library that provides run-time information, by scanning classpath at startup.
This is possible, but not easily. It would need to scan all the classes in the classpath to see if they have an annotation or implement the IProduct interface. See How do you find all subclasses of a given class in Java? for answers to such a problem.
I would do keep it simple and just have a list of classes to load, either in the factory itself, or in an external file (properties file, for example).
Have each product register itself, using a static block like this:
class MyProduct1{
static{
SomeFactory.register(MyProduct1.getClass());
}
..
..
}
An external property file can keep track of all Products.
Your main method can parse this list of Products and do a Class.forName("..").
This way you wouldnt need to code any specific product, just the property file keeps changing. Ah! yes adding security registration would also be a plus point.
Note: I'm just proposing an idea, I'vent tried it myself :)

Categories

Resources