12

Context (Edit)

Some clarification was on demand, so I'll try to sum up what influences the question.

  • The goal of the project is to provide a certain functionality to programmers, most probably in the form of a library (a JAR with class files, I guess).

  • To use said functionality, programmers would have to conform to the constraints that must (should) be satisfied. Otherwise it won't function as expected (just like the locks from java.util.concurrent, that must be acquired / freed at the appropriate time and place).

  • This code won't be the entry point to the applications using it (ie, has no main).

  • There's a limited (and small) amount of operations exposed in the API.

Examples:

  1. Think of a small game, where almost everything is implemented and managed by the already implemented classes. The only thing left for the programmer to do, is to write a method, or a couple of them, that describe what the character will do (walk, change direction, stop, inspect object). I would want to make sure that their methods (possibly marked with an annotation?) just walk, or changeDirection, or calculate diff = desiredValue - x, and not, say, write to some file, or open a socket connection.

  2. Think of a transaction manager. The manager would be provided by this library, as well as some constant attributes of transactions (their isolation level, time-outs, ...). Now, the programmers would like to have transactions and use this manager. I would want to make sure that they only read, write, commit, or rollback on some resources, known to the manager. I wouldn't want them to launchRocket in the middle of the transaction, if the manager does not control any rockets to launch.

The Problem

I want to impose some invariants / restrictions / constraints on the body of a method (or group of methods), to be later implemented by some other programmer, in some other package/location. Say, I give them something along the lines of:

public abstract class ToBeExtended {
    // some private stuff they should not modify
    // ...
    public abstract SomeReturnType safeMethod();
}

It is important (probably imperative), for the purposes of this project, that the method body satisfies some invariants. Or rather, it is imperative that the set of commands this method's implementation uses is limited. Examples of these constraints:

  • This method must not perform any I/O.
  • This method must not instantiate any unknown (potentially dangerous) objects.
  • ...

Put another way:

  • This method can call the methods of a known (specific) class.
  • This method can execute some basic instructions (maths, assign local variables, ifs, loops...).

I've been looking through Annotations, and there seems to be nothing close to this.
My options so far:

  1. Define some annotation, @SafeAnnotation, and apply it to the method, defining a contract with the implementer, that he will follow the rules imposed, or else the system will malfunction.

  2. Define an Enum with the allowed operations. Instead of exposing the allowed methods, only a method is exposed, that accepts a list of these enum objects (or something similar to a Control Flow Graph?) and executes it, giving me the control of what can be done.

Example:

public enum AllowedOperations { OP1, OP2 }

public class TheOneKnown {
    public void executeMyStuff (List<AllowedOperations> ops) {
        // ...
    }
}

My Question

Is there any feature in the language, such as annotations, reflection, or otherwise, allowing me to inspect (either at compile time or runtime) if a method is valid (ie, satisfies my constraints)?
Or rather, is there any way to enforce it to call only a limited set of other methods?

If not (and I think not), would this second approach be a suitable alternative?
Suitable, as in intuitive, well designed and/or good practice.

Update (Progress)

Having had a look at some related questions, I'm also considering (as a third option, maybe) following the steps given in the accepted answer of this question. Although, this may require some rethinking on the architecture.

The whole idea of using annotations to impose restrictions seems to require implementing my own annotation processor. If this is true, I might as well consider a small domain-specific language, so that the programmer would use these limited operations, later translating the code to Java. This way, I would also have control over what is specified.

Community
  • 1
  • 1
afsantos
  • 5,018
  • 4
  • 29
  • 53
  • 3
    Maybe if you wrote your own annotation processor, but nothing short of that. – Louis Wasserman Apr 11 '13 at 21:22
  • That's what I suspected. To allow the programmer to still write code, instead of coding through a list of objects, we'll probably have to write some pre-processor (either for Java, or a small domain-specific language). – afsantos Apr 11 '13 at 21:24
  • 1
    Sounds like what Google do on App Engine - https://developers.google.com/appengine/docs/java/jrewhitelist. I'm afraid I don't know how they do it! Maybe this question also helps - http://stackoverflow.com/questions/1715036/how-do-i-create-a-java-sandbox. – Paul Grime Apr 11 '13 at 21:27
  • Indeed, it sounds similar to defining a whitelist of what can be done. I didn't know about those restrictions on Google App Engine. The difference is that, in this case, the whitelist would only apply to every implementation of that particular method, instead of the whole application. The principles may still apply, though. – afsantos Apr 11 '13 at 21:31
  • If you have a contract you want to enforce for implementation and still want to define an API for other programmers, is your problem not amenable to separation of roles by using an interface? You can provide the implementation you want, roll it into your API, enforce the contract, and still allow for end-users to provide behavior they want within the constraints of the contract. Your question reads a bit like the definition of an interface. – scottb Apr 11 '13 at 21:57
  • @scottb I may have misunterstood your comment. But, to clarify the question, assuming you're familiar with the concept of transaction, think of that method as an implementation of the body of a transaction. It has a limited set of commands it can execute (read, write, commit, rollback), thus satisfying some safety constraints. These constraints are mandatory, in the case of transactions. This is such a case. – afsantos Apr 11 '13 at 22:12
  • @afsantos Where would those checkable method bodies come from? – gaborsch Apr 11 '13 at 23:08
  • @GaborSch Maybe I should add to the question that the goal of this project is to offer some extra functionality to other programmers, most probably a library packed in a JAR. So, presumably, the method bodies I would like to check come from different packages, maybe even a completely different directory in the file system, from the subclasses the programmers are implementing. – afsantos Apr 12 '13 at 06:50

5 Answers5

6

Have a look at java policy files. I've not used them, and I'm not sure they'll fit your problem exactly, but with some digging into the docs they may be a fit. Here's a couple SO questions that may be of help

Limiting file access in Java

What is a simple Java security policy for restricting file writes to a single directory?

And here's some documentation on the policy file.

http://docs.oracle.com/javase/6/docs/technotes/guides/security/PolicyFiles.html

Community
  • 1
  • 1
digitaljoel
  • 25,150
  • 14
  • 83
  • 114
4

You can restrict the classes used by untrusted code with a custom class loader:

public class SafeClassLoader extends ClassLoader {

    Set<String> safe = new HashSet<>();

    {
        String[] s = {
            "java.lang.Object",
            "java.lang.String",
            "java.lang.Integer"
        };
        safe.addAll(Arrays.asList(s));
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        if (safe.contains(name)) {
            return super.loadClass(name, resolve);
        } else {
            throw new ClassNotFoundException(name);
        }
    }
}

public class Sandboxer {
    public static void main(String[] args) throws Exception {
        File f = new File("bin/");
        URL[] urls = {f.toURI().toURL()};
        ClassLoader loader = new URLClassLoader(urls, new SafeClassLoader());
        Class<?> good = loader.loadClass("tools.sandbox.Good");
        System.out.println(good.newInstance().toString());
        Class<?> evil = loader.loadClass("tools.sandbox.Evil");
        System.out.println(evil.newInstance().toString());
    }
}

public class Good {
    @Override
    public String toString() {
        return "I am good";
    }
}

public class Evil {
    @Override
    public String toString() {
        new Thread().start();
        return "I am evil.";
    }
}

Running this will result in

I am good
Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/Thread
    at tools.sandbox.Evil.toString(Evil.java:7)
    at tools.sandbox.Sandboxer.main(Sandboxer.java:18)
Caused by: java.lang.ClassNotFoundException: java.lang.Thread
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 2 more

Of course, this assumes care is taken with the classes you white list. It also can't prevent denial of service stuff such as

while (true) {}

or

new long[1000000000];
meriton
  • 61,876
  • 13
  • 96
  • 163
  • This seems to be an interesting alternative, but, from my understanding, wouldn't the ClassLoader apply to the whole application? Or, suppose the programmers are supposed to extend my class. Can this ClassLoader be used only from some final method of my superclass, for example? – afsantos Apr 12 '13 at 06:46
  • No, several classloaders can coexist. In the above sample application, Sandboxer is loaded from the bootstrap class loader. It wasn't (and couldn't be) loaded from the SafeClassLoader. In your case, you'd load the subclass with untrusted code with the special class loader, and whitelist the superclass in the SafeClassLoader, granting the untrusted code access to that particular class from the bootstrap class loader. – meriton Apr 12 '13 at 11:54
4

I think that the direction in this question is good.

  • Use a specific ClassLoader lo load the class. Beware, that they're an interesting type of horse, it usually happens that the class itself is loaded by a parent classloader. Probably you want some sort of UrlClassLoader, and the parent classloader would be set to the Root classloader It is not enough, though.
  • Use threads to avoid infinite loops (rather implementing Runnable than extending Thread, like there) - this may be unnecessary if you're not worrying about it.
  • Use SecurityManager to avoid java.io operations

In addition to the above, I recommend 2 options:

Give the method a controller, that would contain the functions it can call

For example:

public void foo(Controller ctrl) {
}

public class Controller {
   public boolean commit();
   public boolean rollback();
}

This can give the user a handle, what operations are allowed.

Use an Intent-like command pattern

In Android, the components of the system are quite closed. They cannot directly communicate to each other, they only can fire an event, that "this happened", or "I want to do that".

This way the set of the usable commands are not restricted. Usually, if the methods do only small business logic, that is enough.

Community
  • 1
  • 1
gaborsch
  • 14,381
  • 5
  • 33
  • 43
  • I'll be accepting this answer, as it is very close to what I described in my most recent update, and also describes what I'm intending to try. I think the suggestion about the Controllers and Intents will probably be of some use. I wasn't aware of that Intent mechanic used by Android. – afsantos Apr 17 '13 at 09:37
3

Another alternative will be to use en embedded script interpreter, for example groovy one (https://docs.groovy-lang.org/latest/html/documentation/guide-integrating.html) and to evaluate the third-party methods content at runtime with a pre-execution validation.

Advantage is that you will be able to limit access to only the variables you will bind for the script execution.

You could also write your own validation dsl and apply it, for example using custom annotation, to the method that will execute the script.

pxcv7r
  • 434
  • 5
  • 12
Gab
  • 7,071
  • 2
  • 32
  • 62
0

There are several design by contract libraries available for Java, but I'm not able to recommend one in particular. Java Argument Validation appears to be a lightweight solution, but again, I don't have first-hand experience with it.

Zim-Zam O'Pootertoot
  • 17,440
  • 4
  • 38
  • 67
  • I am an huge fan of design by contract, but, as it stands, in the current version of the requirements, these constraints should be *enforced*, and not only *asked for*. In design by contract, one would say "if you want my service, you should satisfy these pre-conditions, or else I can't give you any guarantee". This case is more like "if you want my service, you *must* satisfy these conditions. There's no way around it". It may still remain as an option, if there is none more suitable, though. – afsantos Apr 11 '13 at 22:30