Concise notes for the impatient learner

Uncategorized

Java Applications with Plugins – Security

Objective

Add security to the extensible Java application created in the previous post. Plugins may come from untrusted sources, and we want to limit what they are able to do (otherwise, we’re basically allowing strangers to run arbitrary code!).

The full source code can be downloaded here.

Application Project

The interface for the Plugin is the same as in the previous post. The PluginClassLoader is also the same.

We’ll have to implement a security policy that limits the permissions of the plugin classes, while preserving the permissions of the other classes in the application. We can differentiate plugin classes by the ClassLoader used to load them (the PluginClassLoader). The code below is adapted from this very helpful post by Jens Nordhal. At first, let’s try to give no permissions to the plugins.

import java.security.AllPermission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.ProtectionDomain;

public class PluginSecurityPolicy extends Policy {
	
    @Override
    public PermissionCollection getPermissions(ProtectionDomain domain) {
        Permissions permissions = new Permissions(); 
		
        if(domain.getClassLoader() instanceof PluginLoader) {  // if it's a plugin
            // no permissions added to the collection
        }
        else {
            permissions.add(new AllPermission());  // give all permissions to other classes
        }
		
        return permissions;
    }
}

We also need to modify the main method to load the SecurityManager and the Policy.

import java.security.Policy;

public class Main {
    public static void main(String[] args) {
		
        // Policy and security manager
        Policy.setPolicy(new PluginSecurityPolicy());
        System.setSecurityManager(new SecurityManager());     
		
        // ... same code as in the previous post ...
}

Plugin Development Project

Same as in the previous post, create a new project, copy the Plugin interface to it, and create a new plugin class implementing the interface. This time, we’re going to change the implementation of the plugin to read a message from a file (which is an operation that requires permission).

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class ByeFilePlugin implements Plugin {

    @Override
    public String getMessage() {
        File file = new File("pluginContent/bye.txt");

        String text = "Error loading the file";
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            text = reader.readLine();
        } catch (IOException e) {
        } finally {
            try {
                reader.close();
            } catch (Exception e) {}
        }

        return text;
    }
}

Compile the file to get a .class file. Then move the .class file into the “plugins” folder in the application project. Create a bye.txt file with a message inside (e.g., “Bye from file”) and place it in the pluginContent folder.

If you try to run the application, you will get an exception. That’s because the plugin does not have permissions to read a file.

Exception in thread "main" java.security.AccessControlException: access denied ("java.io.FilePermission" "pluginContent\bye.txt" "read")
	at java.security.AccessControlContext.checkPermission(Unknown Source)
	at java.security.AccessController.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkRead(Unknown Source)
	at java.io.FileInputStream.(Unknown Source)
	at java.io.FileReader.(Unknown Source)
	at ByeFilePlugin.getMessage(ByeFilePlugin.java:15)

As expected, the plugin is unable to open the file, as it does not have permission to do so. We need to modify the policy to allow opening a file in the pluginContent folder.

import java.io.FilePermission;
import java.security.AllPermission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.ProtectionDomain;

public class PluginSecurityPolicy extends Policy {
	
    @Override
    public PermissionCollection getPermissions(ProtectionDomain domain) {
        Permissions permissions = new Permissions(); 
		
        if(domain.getClassLoader() instanceof PluginLoader) {  // if it's a plugin
            permissions.add(new FilePermission("pluginContent/*", "read"));
        }
        else {
            permissions.add(new AllPermission());  // give all permissions to other classes
        }
		
        return permissions;
    }
}

The plugin is now able to open the file and the content of the file is displayed.

Useful Links

Sandboxing plugins in Java
Great and concise introduction to ProtectionDomains, Permissions, Policy, and SecurityManager.

Adding Plugins to a Java Application
The article uses an older way of setting up the SecurityManager, but it is still a valuable introduction.

Leave a Reply